1 // Copyright 2014 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 #include <errno.h> 6 #include <pthread.h> 7 #include <stdlib.h> 8 9 #include "base/macros.h" 10 #include "base/memory/scoped_ptr.h" 11 #include "components/nacl/loader/nonsfi/irt_interfaces.h" 12 13 namespace nacl { 14 namespace nonsfi { 15 namespace { 16 17 // We heuristically chose 1M for the stack size per thread. 18 const int kStackSize = 1024 * 1024; 19 20 // For RAII of pthread_attr_t. 21 class ScopedPthreadAttrPtr { 22 public: 23 ScopedPthreadAttrPtr(pthread_attr_t* attr) : attr_(attr) { 24 } 25 ~ScopedPthreadAttrPtr() { 26 pthread_attr_destroy(attr_); 27 } 28 29 private: 30 pthread_attr_t* attr_; 31 }; 32 33 struct ThreadContext { 34 void (*start_func)(); 35 void* thread_ptr; 36 }; 37 38 // A thread local pointer to support nacl_irt_tls. 39 // This should be initialized at the beginning of ThreadMain, which is a thin 40 // wrapper of a user function called on a newly created thread, and may be 41 // reset via IrtTlsInit(). The pointer can be obtained via IrtTlsGet(). 42 __thread void* g_thread_ptr; 43 44 void* ThreadMain(void *arg) { 45 ::scoped_ptr<ThreadContext> context(static_cast<ThreadContext*>(arg)); 46 g_thread_ptr = context->thread_ptr; 47 48 // Release the memory of context before running start_func. 49 void (*start_func)() = context->start_func; 50 context.reset(); 51 52 start_func(); 53 abort(); 54 } 55 56 int IrtThreadCreate(void (*start_func)(), void* stack, void* thread_ptr) { 57 pthread_attr_t attr; 58 int error = pthread_attr_init(&attr); 59 if (error != 0) 60 return error; 61 ScopedPthreadAttrPtr scoped_attr_ptr(&attr); 62 63 // Note: Currently we ignore the argument stack. 64 error = pthread_attr_setstacksize(&attr, kStackSize); 65 if (error != 0) 66 return error; 67 68 error = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); 69 if (error != 0) 70 return error; 71 72 ::scoped_ptr<ThreadContext> context(new ThreadContext); 73 context->start_func = start_func; 74 context->thread_ptr = thread_ptr; 75 76 pthread_t tid; 77 error = pthread_create(&tid, &attr, ThreadMain, context.get()); 78 if (error != 0) 79 return error; 80 81 // The ownership of the context is taken by the created thread. So, here we 82 // just manually release it. 83 ignore_result(context.release()); 84 return 0; 85 } 86 87 void IrtThreadExit(int32_t* stack_flag) { 88 // As we actually don't use stack given to thread_create, it means that the 89 // memory can be released whenever. 90 if (stack_flag) 91 *stack_flag = 0; 92 pthread_exit(NULL); 93 } 94 95 int IrtThreadNice(const int nice) { 96 // TODO(https://code.google.com/p/nativeclient/issues/detail?id=3734): 97 // Implement this method. 98 // Note that this is just a hint, so here we just return success without 99 // do anything. 100 return 0; 101 } 102 103 int IrtTlsInit(void* thread_ptr) { 104 g_thread_ptr = thread_ptr; 105 return 0; 106 } 107 108 void* IrtTlsGet() { 109 return g_thread_ptr; 110 } 111 112 } // namespace 113 114 const nacl_irt_thread kIrtThread = { 115 IrtThreadCreate, 116 IrtThreadExit, 117 IrtThreadNice, 118 }; 119 120 const nacl_irt_tls kIrtTls = { 121 IrtTlsInit, 122 IrtTlsGet, 123 }; 124 125 } // namespace nonsfi 126 } // namespace nacl 127