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 : #include "native_client/src/trusted/threading/nacl_thread_interface.h"
8 :
9 : #include "native_client/src/include/nacl_compiler_annotations.h"
10 :
11 : #include "native_client/src/shared/platform/nacl_check.h"
12 : #include "native_client/src/shared/platform/nacl_log.h"
13 : #include "native_client/src/shared/platform/nacl_threads.h"
14 : #include "native_client/src/trusted/nacl_base/nacl_refcount.h"
15 :
16 11 : void WINAPI NaClThreadInterfaceStart(void *data) {
17 : struct NaClThreadInterface *tif =
18 11 : (struct NaClThreadInterface *) data;
19 : void *thread_return;
20 :
21 11 : NaClLog(4,
22 : ("Entered NaClThreadInterfaceStart: thread object 0x%"NACL_PRIxPTR
23 : " starting.\n"),
24 : (uintptr_t) tif); /* NaClThreadId() implicitly printed */
25 11 : (*NACL_VTBL(NaClThreadInterface, tif)->LaunchCallback)(tif);
26 11 : thread_return = (*tif->fn_ptr)(tif);
27 5 : NaClLog(4,
28 : ("NaClThreadInterfaceStart: thread object 0x%"NACL_PRIxPTR
29 : " returned 0x%"NACL_PRIxPTR".\n"),
30 : (uintptr_t) tif,
31 : (uintptr_t) thread_return); /* NaClThreadId() implicitly printed */
32 5 : (*NACL_VTBL(NaClThreadInterface, tif)->Exit)(tif, thread_return);
33 0 : NaClLog(LOG_FATAL,
34 : "NaClThreadInterface: Exit member function did not exit thread\n");
35 0 : }
36 :
37 : int NaClThreadInterfaceCtor_protected(
38 : struct NaClThreadInterface *self,
39 : NaClThreadIfFactoryFunction factory,
40 : void *factory_data,
41 : NaClThreadIfStartFunction fn_ptr,
42 : void *thread_data,
43 11 : size_t thread_stack_size) {
44 :
45 11 : NaClLog(3, "Entered NaClThreadInterfaceThreadPlacementFactory\n");
46 11 : if (!NaClRefCountCtor((struct NaClRefCount *) self)) {
47 0 : NaClLog(3,
48 : "NaClThreadInterfaceThreadPlacementFactory,"
49 : " NaClRefCountCtor base class ctor failed\n");
50 0 : return 0;
51 : }
52 :
53 11 : self->factory = factory;
54 11 : self->factory_data = factory_data;
55 11 : self->thread_stack_size = thread_stack_size;
56 11 : self->fn_ptr = fn_ptr;
57 11 : self->thread_data = thread_data;
58 11 : self->thread_started = 0;
59 11 : NACL_VTBL(NaClRefCount, self) =
60 : (struct NaClRefCountVtbl const *) &kNaClThreadInterfaceVtbl;
61 11 : NaClLog(3,
62 : "Leaving NaClThreadInterfaceThreadPlacementFactory, returning 1\n");
63 11 : return 1;
64 : }
65 :
66 : int NaClThreadInterfaceThreadFactory(
67 : void *factory_data,
68 : NaClThreadIfStartFunction fn_ptr,
69 : void *thread_data,
70 : size_t thread_stack_size,
71 0 : struct NaClThreadInterface **out_new_thread) {
72 : struct NaClThreadInterface *new_thread;
73 : int rv;
74 :
75 0 : NaClLog(3, "Entered NaClThreadInterfaceThreadFactory\n");
76 0 : new_thread = malloc(sizeof *new_thread);
77 0 : if (NULL == new_thread) {
78 0 : NaClLog(3, "NaClThreadInterfaceThreadFactory: no memory!\n");
79 0 : return 0;
80 : }
81 0 : if (0 != (rv =
82 : NaClThreadInterfaceCtor_protected(
83 : new_thread,
84 : NaClThreadInterfaceThreadFactory,
85 : factory_data,
86 : fn_ptr,
87 : thread_data,
88 : thread_stack_size))) {
89 0 : *out_new_thread = new_thread;
90 0 : NaClLog(3,
91 : "NaClThreadInterfaceThreadFactory: new thread object"
92 : " 0x%"NACL_PRIxPTR" (not started)\n",
93 : (uintptr_t) new_thread);
94 0 : new_thread = NULL;
95 : }
96 0 : free(new_thread);
97 0 : NaClLog(3,
98 : "Leaving NaClThreadInterfaceThreadFactory, returning %d\n",
99 : rv);
100 0 : return rv;
101 : }
102 :
103 0 : void NaClThreadInterfaceDtor(struct NaClRefCount *vself) {
104 : struct NaClThreadInterface *self =
105 0 : (struct NaClThreadInterface *) vself;
106 0 : CHECK(self->thread_started == 0);
107 0 : self->fn_ptr = NULL;
108 0 : self->thread_data = NULL;
109 0 : NACL_VTBL(NaClRefCount, self) = &kNaClRefCountVtbl;
110 0 : (*NACL_VTBL(NaClRefCount, self)->Dtor)(vself);
111 0 : }
112 :
113 11 : int NaClThreadInterfaceStartThread(struct NaClThreadInterface *self) {
114 : int rv;
115 :
116 11 : NaClLog(3,
117 : "Entered NaClThreadInterfaceStartThread: self 0x%"NACL_PRIxPTR"\n",
118 : (uintptr_t) self);
119 11 : CHECK(self->thread_started == 0);
120 :
121 11 : rv = NaClThreadCtor(&self->thread,
122 : NaClThreadInterfaceStart,
123 : self,
124 : self->thread_stack_size);
125 11 : if (rv) {
126 11 : self->thread_started = 1;
127 : }
128 11 : NaClLog(3, "Leaving NaClThreadInterfaceStartThread, rv=%d\n", rv);
129 11 : return rv;
130 : }
131 :
132 : /*
133 : * Default LaunchCallback does nothing. We could have made this "pure
134 : * virtual" by doing NaClLog(LOG_FATAL, ...) in the body (at least
135 : * detected at runtime).
136 : */
137 0 : void NaClThreadInterfaceLaunchCallback(struct NaClThreadInterface *self) {
138 0 : NaClLog(3,
139 : "NaClThreadInterfaceLaunchCallback: thread 0x%"NACL_PRIxPTR"\n",
140 : (uintptr_t) self);
141 0 : }
142 :
143 : void NaClThreadInterfaceExit(struct NaClThreadInterface *self,
144 0 : void *exit_code) {
145 0 : NaClLog(3,
146 : "NaClThreadInterfaceExit: thread 0x%"NACL_PRIxPTR"\n",
147 : (uintptr_t) self);
148 0 : self->thread_started = 0; /* on way out */
149 0 : NaClRefCountUnref((struct NaClRefCount *) self);
150 : /* only keep low order bits of the traditional void* return */
151 0 : NaClThreadExit((int) (uintptr_t) exit_code);
152 0 : }
153 :
154 : struct NaClThreadInterfaceVtbl const kNaClThreadInterfaceVtbl = {
155 : {
156 : NaClThreadInterfaceDtor,
157 : },
158 : NaClThreadInterfaceStartThread,
159 : NaClThreadInterfaceLaunchCallback,
160 : NaClThreadInterfaceExit,
161 : };
162 :
163 : int NaClThreadInterfaceConstructAndStartThread(
164 : NaClThreadIfFactoryFunction factory_fn,
165 : void *factory_data,
166 : NaClThreadIfStartFunction thread_fn_ptr,
167 : void *thread_data,
168 : size_t thread_stack_size,
169 11 : struct NaClThreadInterface **out_new_thread) {
170 : struct NaClThreadInterface *new_thread;
171 :
172 11 : NaClLog(3,
173 : "NaClThreadInterfaceConstructAndStartThread: invoking factory"
174 : " function 0x%"NACL_PRIxPTR", factory data 0x%"NACL_PRIxPTR"\n",
175 : (uintptr_t) factory_fn, (uintptr_t) factory_data);
176 11 : if (!(*factory_fn)(factory_data,
177 : thread_fn_ptr,
178 : thread_data,
179 : thread_stack_size,
180 : &new_thread)) {
181 0 : NaClLog(3,
182 : ("NaClThreadInterfaceConstructAndStartThread:"
183 : " factory 0x%"NACL_PRIxPTR" failed to produce!\n"),
184 : (uintptr_t) factory_fn);
185 0 : new_thread = NULL;
186 0 : goto abort;
187 : }
188 11 : NaClLog(3,
189 : "NaClThreadInterfaceConstructAndStartThread: StartThread vfn\n");
190 11 : if (!(*NACL_VTBL(NaClThreadInterface, new_thread)->StartThread)(
191 : new_thread)) {
192 0 : NaClLog(3,
193 : ("NaClThreadInterfaceConstructAndStartThread:"
194 : " factory 0x%"NACL_PRIxPTR" produced a thread 0x%"NACL_PRIxPTR
195 : " that won't start!\n"),
196 : (uintptr_t) factory_fn,
197 : (uintptr_t) new_thread);
198 0 : NaClRefCountUnref((struct NaClRefCount *) new_thread);
199 0 : new_thread = NULL;
200 0 : goto abort;
201 : }
202 11 : NaClLog(4,
203 : ("NaClThreadInterfaceConstructAndStartThread: thread 0x%"NACL_PRIxPTR
204 : " started\n"),
205 : (uintptr_t) new_thread);
206 11 : abort:
207 11 : *out_new_thread = new_thread;
208 11 : return new_thread != NULL;
209 : }
|