function porting_abstraction_layer_thread_start

From liblfds.org
Jump to navigation Jump to search

Source Files

└───test
    └───src
        └───porting_abstraction_layer_thread_start.c

Prototype

int test_pal_thread_start( test_pal_thread_state_t *thread_state,
                           struct test_pal_logical_processor *lp, 
                           test_pal_thread_return_t (TEST_PAL_CALLING_CONVENTION *thread_function)(void *thread_user_state),
                           void *thread_user_state );

Parameters

test_pal_thread_state_t *thread_state

A pointer to a test_pal_thread_state_t, which is set to the thread state for the newly started thread.

struct test_pal_logical_processor *lp

A pointer to a struct test_pal_logical_processor. which indicates which logical core the new thread should be pinned to.

test_pal_thread_return_t (TEST_PAL_CALLING_CONVENTION *thread_function)(void *thread_user_state)

The thread function.

void *thread_user_state

This is the void pointer which is passed to the thread function as its argument.

Return Value

The return value is 1 if the thread has been successfully created, 0 otherwise.

Notes

This function starts a thread, using the thread function thread_function, passing it the argument thread_user_state, and pins the thread to the logical processor specified by *lp. Pinning threads can be awkward. An example of this is under Android, where the normal POSIX function for affinity is not supported, such that on that platform only the thread itself can change its own affinity (i.e. it cannot be created with an affinity), and so the implementation actually starts the thread with a 'first-stage' thread function, which sets the thread affinity, and then calls the thread function specified by the thread_function argument.

Example

int test_pal_thread_start( test_pal_thread_state_t *thread_state,
                           struct test_pal_logical_processor *lp,
                           test_pal_thread_return_t (TEST_PAL_CALLING_CONVENTION *thread_function)(void *thread_user_state),
                           void *thread_user_state )
{
  int
    rv = 0;

  DWORD
    thread_id;

  DWORD_PTR
    affinity_mask,
    result;

  assert( thread_state != NULL );
  assert( lp != NULL );
  assert( thread_function != NULL );
  // TRD : thread_user_state can be NULL

  /* TRD : Vista and earlier do not support processor groups
           as such, there is a single implicit processor group
           also, there's no support for actually starting a thread in its correct NUMA node / logical processor
           so we make the best of it; we start suspended, set the affinity, and then resume
           the thread itself internally is expected to be making allocs from the correct NUMA node
  */

  *thread_state = CreateThread( NULL, 0, thread_function, thread_user_state, CREATE_SUSPENDED, &thread_id );

  affinity_mask = (DWORD_PTR) (1 << lp->logical_processor_number);

  SetThreadAffinityMask( *thread_state, affinity_mask );

  ResumeThread( *thread_state );

  if( *thread_state != NULL )
    rv = 1;

  return( rv );
}

See Also