OLD | NEW |
---|---|
1 /* | 1 /* |
2 * Copyright 2014 The Native Client Authors. All rights reserved. | 2 * Copyright 2014 The Native Client Authors. All rights reserved. |
3 * Use of this source code is governed by a BSD-style license that can be | 3 * Use of this source code is governed by a BSD-style license that can be |
4 * found in the LICENSE file. | 4 * found in the LICENSE file. |
5 */ | 5 */ |
6 | 6 |
7 #include <assert.h> | |
7 #include <errno.h> | 8 #include <errno.h> |
8 | 9 |
10 #include "native_client/src/nonsfi/linux/linux_pthread_private.h" | |
9 #include "native_client/src/nonsfi/linux/linux_syscall_defines.h" | 11 #include "native_client/src/nonsfi/linux/linux_syscall_defines.h" |
10 #include "native_client/src/nonsfi/linux/linux_syscall_structs.h" | 12 #include "native_client/src/nonsfi/linux/linux_syscall_structs.h" |
11 #include "native_client/src/nonsfi/linux/linux_syscall_wrappers.h" | 13 #include "native_client/src/nonsfi/linux/linux_syscall_wrappers.h" |
12 #include "native_client/src/nonsfi/linux/linux_sys_private.h" | 14 #include "native_client/src/nonsfi/linux/linux_sys_private.h" |
13 #include "native_client/src/public/linux_syscalls/sched.h" | 15 #include "native_client/src/public/linux_syscalls/sched.h" |
14 #include "native_client/src/public/linux_syscalls/sys/syscall.h" | 16 #include "native_client/src/public/linux_syscalls/sys/syscall.h" |
15 #include "native_client/src/untrusted/nacl/nacl_irt.h" | 17 #include "native_client/src/untrusted/nacl/nacl_irt.h" |
16 #include "native_client/src/untrusted/nacl/nacl_thread.h" | 18 #include "native_client/src/untrusted/nacl/nacl_thread.h" |
17 #include "native_client/src/untrusted/pthread/pthread_internal.h" | 19 #include "native_client/src/untrusted/pthread/pthread_internal.h" |
18 | 20 |
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
72 : "r7"); | 74 : "r7"); |
73 #else | 75 #else |
74 # error Unsupported architecture | 76 # error Unsupported architecture |
75 #endif | 77 #endif |
76 } | 78 } |
77 | 79 |
78 static int nacl_irt_thread_nice(const int nice) { | 80 static int nacl_irt_thread_nice(const int nice) { |
79 return 0; | 81 return 0; |
80 } | 82 } |
81 | 83 |
84 static struct nc_combined_tdb *get_irt_tdb(void *thread_ptr) { | |
85 struct nc_combined_tdb *tdb = (void *) ((uintptr_t) thread_ptr + | |
86 __nacl_tp_tdb_offset(sizeof(*tdb))); | |
87 return tdb; | |
88 } | |
89 | |
90 /* Initialize a newly allocated TDB to some default values. */ | |
91 static void nc_tdb_init(nc_thread_descriptor_t *tdb, | |
Mark Seaborn
2015/07/08 04:11:21
Rather than duplicating this from pthread/nc_threa
Luis Héctor Chávez
2015/07/08 16:42:13
Done.
| |
92 nc_basic_thread_data_t *basic_data) { | |
93 tdb->tls_base = tdb; | |
94 tdb->joinable = PTHREAD_CREATE_JOINABLE; | |
95 tdb->join_waiting = 0; | |
96 tdb->rdlock_count = 0; | |
97 tdb->stack_node = NULL; | |
98 tdb->tls_node = NULL; | |
99 tdb->start_func = NULL; | |
100 tdb->state = NULL; | |
101 tdb->irt_thread_data = NULL; | |
102 tdb->basic_data = basic_data; | |
103 | |
104 basic_data->retval = NULL; | |
105 basic_data->status = THREAD_RUNNING; | |
106 if (pthread_cond_init(&basic_data->join_condvar, NULL) != 0) | |
107 __builtin_trap(); | |
108 basic_data->tdb = tdb; | |
109 } | |
110 | |
111 /* | |
112 * This is used by the IRT for user threads. We initialize all fields | |
113 * so that we get predictable behaviour in case some IRT code does an | |
114 * unsupported pthread operation on a user thread. | |
115 */ | |
116 void __nc_initialize_unjoinable_thread(struct nc_combined_tdb *tdb) { | |
117 nc_tdb_init(&tdb->tdb, &tdb->basic_data); | |
118 tdb->tdb.joinable = 0; | |
119 } | |
120 | |
121 /* | |
122 * This is the real first entry point for new threads. | |
123 */ | |
124 static void irt_start_thread() { | |
Mark Seaborn
2015/07/08 04:11:21
Can you add a comment saying that this is based on
Luis Héctor Chávez
2015/07/08 16:42:13
Done.
| |
125 struct nc_combined_tdb *tdb = get_irt_tdb(__nacl_read_tp()); | |
126 | |
127 /* | |
128 * Fetch the user's start routine. | |
129 */ | |
130 void *(*user_start)(void *) = tdb->tdb.start_func; | |
131 | |
132 /* | |
133 * Now do per-thread initialization for the IRT-private C library state. | |
134 */ | |
135 __newlib_thread_init(); | |
136 | |
137 /* | |
138 * Finally, run the user code. | |
139 */ | |
140 (*user_start)(tdb->tdb.state); | |
141 | |
142 /* | |
143 * That should never return. Crash hard if it does. | |
144 */ | |
145 __builtin_trap(); | |
146 } | |
147 | |
148 int nacl_user_thread_create(void *(*start_func)(void *), void *stack, | |
149 void *thread_ptr) { | |
150 struct nc_combined_tdb *tdb; | |
151 | |
152 /* | |
153 * Before we start the thread, allocate the IRT-private TLS area for it. | |
154 */ | |
155 size_t combined_size = __nacl_tls_combined_size(sizeof(*tdb)); | |
156 void *combined_area = malloc(combined_size); | |
157 if (combined_area == NULL) | |
158 return EAGAIN; | |
159 | |
160 /* | |
Mark Seaborn
2015/07/08 04:11:21
Nit: fix indentation
Luis Héctor Chávez
2015/07/08 16:42:13
Done.
| |
161 * Note that __nacl_tls_initialize_memory() is not reversible, | |
162 * because it takes a pointer that need not be aligned and can | |
163 * return a pointer that is aligned. In order to | |
164 * free(combined_area) later, we must save the value of | |
165 * combined_area. | |
166 */ | |
167 void *irt_tp = __nacl_tls_initialize_memory(combined_area, sizeof(*tdb)); | |
Mark Seaborn
2015/07/08 04:11:21
Nit: fix indentation
Luis Héctor Chávez
2015/07/08 16:42:13
Done.
| |
168 tdb = get_irt_tdb(irt_tp); | |
169 __nc_initialize_unjoinable_thread(tdb); | |
170 tdb->tdb.irt_thread_data = combined_area; | |
171 tdb->tdb.start_func = start_func; | |
172 tdb->tdb.state = thread_ptr; | |
173 | |
174 return nacl_irt_thread_create(irt_start_thread, stack, irt_tp); | |
175 } | |
176 | |
177 void nacl_user_thread_exit(int32_t *stack_flag) { | |
178 struct nc_combined_tdb *tdb = get_irt_tdb(__nacl_read_tp()); | |
179 | |
180 __nc_tsd_exit(); | |
181 | |
182 /* | |
183 * Sanity check: Check that this function was not called on a thread | |
184 * created by the IRT's internal pthread_create(). For such | |
185 * threads, irt_thread_data == NULL. | |
186 */ | |
187 assert(tdb->tdb.irt_thread_data != NULL); | |
188 | |
189 free(tdb->tdb.irt_thread_data); | |
190 | |
191 nacl_irt_thread_exit(stack_flag); | |
192 } | |
193 | |
82 void __nc_initialize_interfaces(void) { | 194 void __nc_initialize_interfaces(void) { |
83 const struct nacl_irt_thread init = { | 195 const struct nacl_irt_thread init = { |
84 nacl_irt_thread_create, | 196 nacl_irt_thread_create, |
85 nacl_irt_thread_exit, | 197 nacl_irt_thread_exit, |
86 nacl_irt_thread_nice, | 198 nacl_irt_thread_nice, |
87 }; | 199 }; |
88 __libnacl_irt_thread = init; | 200 __libnacl_irt_thread = init; |
89 } | 201 } |
OLD | NEW |