Home | History | Annotate | Download | only in tests
      1 /* Copyright (c) 2011 The Chromium Authors. All rights reserved.
      2  * Use of this source code is governed by a BSD-style license that can be
      3  * found in the LICENSE file.
      4  */
      5 
      6 #ifndef PPAPI_TESTS_PP_THREAD_H_
      7 #define PPAPI_TESTS_PP_THREAD_H_
      8 
      9 #include "ppapi/c/pp_macros.h"
     10 #include "ppapi/tests/test_utils.h"
     11 
     12 #if defined(PPAPI_POSIX)
     13 #include <pthread.h>
     14 #elif defined(PPAPI_OS_WIN)
     15 #include <process.h>
     16 #include <windows.h>
     17 #else
     18 #error No thread library detected.
     19 #endif
     20 
     21 /**
     22  * @file
     23  * This file provides platform-independent wrappers around threads. This is for
     24  * use by PPAPI wrappers and tests which need to run on multiple platforms to
     25  * support both trusted platforms (Windows, Mac, Linux) and untrusted (Native
     26  * Client). Apps that use PPAPI only with Native Client should generally use the
     27  * Native Client POSIX implementation instead.
     28  *
     29  * TODO(dmichael): Move this file to ppapi/c and delete this comment, if we end
     30  * up needing platform independent threads in PPAPI C or C++. This file was
     31  * written using inline functions and PPAPI naming conventions with the intent
     32  * of making it possible to put it in to ppapi/c. Currently, however, it's only
     33  * used in ppapi/tests, so is not part of the published API.
     34  */
     35 
     36 typedef void (PP_ThreadFunction)(void* data);
     37 
     38 #if defined(PPAPI_POSIX)
     39 typedef pthread_t PP_Thread;
     40 #elif defined(PPAPI_OS_WIN)
     41 struct PP_Thread {
     42   HANDLE handle;
     43   PP_ThreadFunction* thread_func;
     44   void* thread_arg;
     45 };
     46 #endif
     47 
     48 PP_INLINE bool PP_CreateThread(PP_Thread* thread,
     49                                PP_ThreadFunction function,
     50                                void* thread_arg);
     51 PP_INLINE void PP_JoinThread(PP_Thread thread);
     52 
     53 #if defined(PPAPI_POSIX)
     54 /* Because POSIX thread functions return void* and Windows thread functions do
     55  * not, we make PPAPI thread functions have the least capability (no returns).
     56  * This struct wraps the user data & function so that we can use the correct
     57  * function type on POSIX platforms.
     58  */
     59 struct PP_ThreadFunctionArgWrapper {
     60   void* user_data;
     61   PP_ThreadFunction* user_function;
     62 };
     63 
     64 PP_INLINE void* PP_POSIXThreadFunctionThunk(void* posix_thread_arg) {
     65   PP_ThreadFunctionArgWrapper* arg_wrapper =
     66       (PP_ThreadFunctionArgWrapper*)posix_thread_arg;
     67   arg_wrapper->user_function(arg_wrapper->user_data);
     68   free(posix_thread_arg);
     69   return NULL;
     70 }
     71 
     72 PP_INLINE bool PP_CreateThread(PP_Thread* thread,
     73                                PP_ThreadFunction function,
     74                                void* thread_arg) {
     75   PP_ThreadFunctionArgWrapper* arg_wrapper =
     76       (PP_ThreadFunctionArgWrapper*)malloc(sizeof(PP_ThreadFunctionArgWrapper));
     77   arg_wrapper->user_function = function;
     78   arg_wrapper->user_data = thread_arg;
     79   return (pthread_create(thread,
     80                          NULL,
     81                          PP_POSIXThreadFunctionThunk,
     82                          arg_wrapper) == 0);
     83 }
     84 
     85 PP_INLINE void PP_JoinThread(PP_Thread thread) {
     86   void* exit_status;
     87   pthread_join(thread, &exit_status);
     88 }
     89 
     90 #elif defined(PPAPI_OS_WIN)
     91 
     92 PP_INLINE unsigned __stdcall PP_WindowsThreadFunction(void* param) {
     93   PP_Thread* thread = reinterpret_cast<PP_Thread*>(param);
     94   thread->thread_func(thread->thread_arg);
     95   return 0;
     96 }
     97 
     98 PP_INLINE bool PP_CreateThread(PP_Thread* thread,
     99                                PP_ThreadFunction function,
    100                                void* thread_arg) {
    101   if (!thread)
    102     return false;
    103   thread->thread_func = function;
    104   thread->thread_arg = thread_arg;
    105   uintptr_t raw_handle = ::_beginthreadex(NULL,
    106                                           0,  /* Use default stack size. */
    107                                           &PP_WindowsThreadFunction,
    108                                           thread,
    109                                           0,
    110                                           NULL);
    111   thread->handle = reinterpret_cast<HANDLE>(raw_handle);
    112   return (thread->handle != NULL);
    113 }
    114 
    115 PP_INLINE void PP_JoinThread(PP_Thread thread) {
    116   ::WaitForSingleObject(thread.handle, INFINITE);
    117   ::CloseHandle(thread.handle);
    118 }
    119 
    120 #endif
    121 
    122 
    123 /**
    124  * @}
    125  */
    126 
    127 #endif  /* PPAPI_TESTS_PP_THREAD_H_ */
    128 
    129