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