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