1 : /*
2 : * Copyright (c) 2011 The Native Client 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 : /*
8 : * NaCl Server Runtime threads implementation layer.
9 : */
10 :
11 : #include <stdlib.h>
12 : /*
13 : * We need sys/mman.h for PAGE_SIZE on Android. PAGE_SIZE is what
14 : * PTHREAD_STACK_MIN defined to, so Android's pthread.h is somewhat
15 : * buggy in that regard.
16 : */
17 : #include <sys/mman.h>
18 : #include <sys/types.h>
19 : #include <signal.h>
20 : #include <pthread.h>
21 : #include <limits.h>
22 : /*
23 : * PTHREAD_STACK_MIN should come from pthread.h as documented, but is
24 : * actually pulled in by limits.h.
25 : */
26 :
27 : #include "native_client/src/include/portability.h"
28 : #include "native_client/src/shared/platform/nacl_log.h"
29 : #include "native_client/src/shared/platform/nacl_threads.h"
30 : #include "native_client/src/trusted/service_runtime/nacl_config.h"
31 :
32 : #if !defined(__native_client__) && NACL_KERN_STACK_SIZE < PTHREAD_STACK_MIN
33 : # error "NaCl service runtime stack size is smaller than PTHREAD_STACK_MIN"
34 : #endif
35 :
36 41436 : static int NaClThreadCreate(struct NaClThread *ntp,
37 : void (*start_fn)(void *),
38 : void *state,
39 : size_t stack_size,
40 : int is_detached) {
41 : pthread_attr_t attr;
42 : int code;
43 : int rv;
44 :
45 41436 : rv = 0;
46 :
47 41436 : if (stack_size < PTHREAD_STACK_MIN) {
48 4 : stack_size = PTHREAD_STACK_MIN;
49 : }
50 41436 : if (0 != (code = pthread_attr_init(&attr))) {
51 0 : NaClLog(LOG_ERROR,
52 : "NaClThreadCtor: pthread_atr_init returned %d",
53 : code);
54 0 : goto done;
55 : }
56 41436 : if (0 != (code = pthread_attr_setstacksize(&attr, stack_size))) {
57 0 : NaClLog(LOG_ERROR,
58 : "NaClThreadCtor: pthread_attr_setstacksize returned %d",
59 : code);
60 0 : goto done_attr_dtor;
61 : }
62 41436 : if (is_detached) {
63 41406 : if (0 != (code = pthread_attr_setdetachstate(&attr,
64 : PTHREAD_CREATE_DETACHED))) {
65 0 : NaClLog(LOG_ERROR,
66 : "nacl_thread: pthread_attr_setdetachstate returned %d",
67 : code);
68 0 : goto done_attr_dtor;
69 : }
70 : }
71 41436 : if (0 != (code = pthread_create(&ntp->tid,
72 : &attr,
73 : (void *(*)(void *)) start_fn,
74 : state))) {
75 0 : NaClLog(LOG_ERROR,
76 : "nacl_thread: pthread_create returned %d",
77 : code);
78 0 : goto done_attr_dtor;
79 : }
80 41436 : rv = 1;
81 : done_attr_dtor:
82 41436 : (void) pthread_attr_destroy(&attr); /* often a noop */
83 : done:
84 41436 : return rv;
85 : }
86 :
87 : /*
88 : * Even if ctor fails, it should be okay -- and required -- to invoke
89 : * the dtor on it.
90 : */
91 41406 : int NaClThreadCtor(struct NaClThread *ntp,
92 : void (*start_fn)(void *),
93 : void *state,
94 : size_t stack_size) {
95 41406 : return NaClThreadCreate(ntp, start_fn, state, stack_size,
96 : /* is_detached= */ 1);
97 : }
98 :
99 30 : int NaClThreadCreateJoinable(struct NaClThread *ntp,
100 : void (*start_fn)(void *),
101 : void *state,
102 : size_t stack_size) {
103 30 : return NaClThreadCreate(ntp, start_fn, state, stack_size,
104 : /* is_detached= */ 0);
105 : }
106 :
107 40527 : void NaClThreadDtor(struct NaClThread *ntp) {
108 : /*
109 : * The threads that we create are not joinable, and we cannot tell
110 : * when they are truly gone. Fortunately, the threads themselves
111 : * and the underlying thread library are responsible for ensuring
112 : * that resources such as the thread stack are properly released.
113 : */
114 : UNREFERENCED_PARAMETER(ntp);
115 40527 : }
116 :
117 30 : void NaClThreadJoin(struct NaClThread *ntp) {
118 30 : pthread_join(ntp->tid, NULL);
119 30 : }
120 :
121 40541 : void NaClThreadExit(void) {
122 40541 : pthread_exit(NULL);
123 : }
124 :
125 446584 : void NaClThreadYield(void) {
126 446584 : sched_yield();
127 440644 : }
|