1 /* 2 * Copyright (c) 2014 The Chromium Authors. All rights reserved. 3 * Use of this source code is governed by a BSD-style license that can be 4 * found in the LICENSE file. 5 */ 6 7 #include <pthread.h> 8 9 #include "irt_syscalls.h" 10 #include "ppapi/c/pp_module.h" 11 #include "ppapi/c/ppp.h" 12 13 struct PP_StartFunctions { 14 int32_t (*PPP_InitializeModule)(PP_Module module_id, 15 PPB_GetInterface get_browser_interface); 16 void (*PPP_ShutdownModule)(); 17 const void* (*PPP_GetInterface)(const char* interface_name); 18 }; 19 20 struct PP_ThreadFunctions { 21 /* 22 * This is a cut-down version of pthread_create()/pthread_join(). 23 * We omit thread creation attributes and the thread's return value. 24 * 25 * We use uintptr_t as the thread ID type because pthread_t is not 26 * part of the stable ABI; a user thread library might choose an 27 * arbitrary size for its own pthread_t. 28 */ 29 int (*thread_create)(uintptr_t* tid, 30 void (*func)(void* thread_argument), 31 void* thread_argument); 32 int (*thread_join)(uintptr_t tid); 33 }; 34 35 #define NACL_IRT_PPAPIHOOK_v0_1 "nacl-irt-ppapihook-0.1" 36 struct nacl_irt_ppapihook { 37 int (*ppapi_start)(const struct PP_StartFunctions*); 38 void (*ppapi_register_thread_creator)(const struct PP_ThreadFunctions*); 39 }; 40 41 42 static int thread_create(uintptr_t *tid, 43 void (*func)(void *thread_argument), 44 void *thread_argument) { 45 /* 46 * We know that newlib and glibc use a small pthread_t type, so we 47 * do not need to wrap pthread_t values. 48 */ 49 return pthread_create((pthread_t *) tid, NULL, 50 (void *(*)(void *thread_argument)) func, 51 thread_argument); 52 } 53 54 static int thread_join(uintptr_t tid) { 55 return pthread_join((pthread_t) tid, NULL); 56 } 57 58 /* 59 * These are dangling references to functions that the application must define. 60 */ 61 static const struct PP_StartFunctions ppapi_app_start_callbacks = { 62 PPP_InitializeModule, 63 PPP_ShutdownModule, 64 PPP_GetInterface 65 }; 66 67 const static struct PP_ThreadFunctions thread_funcs = { 68 thread_create, 69 thread_join 70 }; 71 72 static void fatal_error(const char *message) { 73 write(2, message, strlen(message)); 74 _exit(127); 75 } 76 77 /* 78 * We cannot tell at link time whether the application uses PPB_Audio, 79 * because of the way that PPAPI is defined via runtime interface 80 * query rather than a set of static functions. This means that we 81 * register the audio thread functions unconditionally. This adds the 82 * small overhead of pulling in pthread_create() even if the 83 * application does not use PPB_Audio or libpthread. 84 * 85 * If an application developer wants to avoid that cost, they can 86 * override this function with an empty definition. 87 */ 88 void __nacl_register_thread_creator(const struct nacl_irt_ppapihook *hooks) { 89 hooks->ppapi_register_thread_creator(&thread_funcs); 90 } 91 92 int PpapiPluginStart(const struct PP_StartFunctions *funcs) { 93 struct nacl_irt_ppapihook hooks; 94 if (sizeof(hooks) != __nacl_irt_query(NACL_IRT_PPAPIHOOK_v0_1, 95 &hooks, sizeof(hooks))) { 96 fatal_error("PpapiPluginStart: PPAPI hooks not found\n"); 97 } 98 99 __nacl_register_thread_creator(&hooks); 100 return hooks.ppapi_start(funcs); 101 } 102 103 104 /* 105 * The application's main (or the one supplied in this library) calls this 106 * to start the PPAPI world. 107 */ 108 int PpapiPluginMain(void) { 109 return PpapiPluginStart(&ppapi_app_start_callbacks); 110 } 111