@@ -47,9 +47,82 @@ void _emscripten_dlopen_js(struct dso* handle,
47
47
void __dl_vseterr (const char * , va_list );
48
48
49
49
static struct dso * _Atomic head , * _Atomic tail ;
50
+
51
+ #ifdef _REENTRANT
50
52
static thread_local struct dso * thread_local_tail ;
51
53
static pthread_rwlock_t lock ;
52
54
55
+ static void dlsync_locked () {
56
+ if (!thread_local_tail ) {
57
+ thread_local_tail = head ;
58
+ }
59
+ while (thread_local_tail -> next ) {
60
+ struct dso * p = thread_local_tail -> next ;
61
+ dbg ("dlsync_locked: %s mem_addr=%p "
62
+ "mem_size=%zu table_addr=%p table_size=%zu" ,
63
+ p -> name ,
64
+ p -> mem_addr ,
65
+ p -> mem_size ,
66
+ p -> table_addr ,
67
+ p -> table_size );
68
+ void * success = _dlopen_js (p );
69
+ if (!success ) {
70
+ // If any on the libraries fails to load here then we give up.
71
+ // TODO(sbc): Ideally this would never happen and we could/should
72
+ // abort, but on the main thread (where we don't have sync xhr) its
73
+ // often not possible to syncronously load side module.
74
+ _emscripten_errf ("_dlopen_js failed: %s" , dlerror ());
75
+ break ;
76
+ }
77
+ thread_local_tail = p ;
78
+ }
79
+ }
80
+
81
+ // This function is called from emscripten_yield which itself is called whenever
82
+ // we block on a futex. We need to check to avoid infinite recursion when
83
+ // taking the lock below.
84
+ static thread_local bool skip_dlsync = false;
85
+
86
+ static void ensure_init ();
87
+
88
+ void _emscripten_thread_sync_code () {
89
+ if (skip_dlsync ) {
90
+ return ;
91
+ }
92
+ skip_dlsync = true;
93
+ ensure_init ();
94
+ if (thread_local_tail != tail ) {
95
+ dbg ("emscripten_thread_sync_code: catching up %p %p" , thread_local_tail , tail );
96
+ pthread_rwlock_rdlock (& lock );
97
+ dlsync_locked ();
98
+ pthread_rwlock_unlock (& lock );
99
+ dbg ("emscripten_thread_sync_code: done" );
100
+ }
101
+ skip_dlsync = false;
102
+ }
103
+
104
+ static void do_read_lock () {
105
+ skip_dlsync = true;
106
+ pthread_rwlock_rdlock (& lock );
107
+ }
108
+
109
+ static void do_write_lock () {
110
+ // Once we have the lock we want to avoid automatic code sync as that would
111
+ // result in a deadlock.
112
+ skip_dlsync = true;
113
+ pthread_rwlock_wrlock (& lock );
114
+ }
115
+
116
+ static void do_unlock () {
117
+ pthread_rwlock_unlock (& lock );
118
+ skip_dlsync = false;
119
+ }
120
+ #else
121
+ #define do_unlock ()
122
+ #define do_read_lock ()
123
+ #define do_write_lock ()
124
+ #endif
125
+
53
126
static void error (const char * fmt , ...) {
54
127
va_list ap ;
55
128
va_start (ap , fmt );
@@ -80,13 +153,16 @@ static void load_library_done(struct dso* p) {
80
153
p -> table_addr ,
81
154
p -> table_size );
82
155
156
+ #ifdef _REENTRANT
157
+ thread_local_tail = p ;
158
+ #endif
159
+
83
160
// insert into linked list
84
161
p -> prev = tail ;
85
162
if (tail ) {
86
163
tail -> next = p ;
87
164
}
88
165
tail = p ;
89
- thread_local_tail = p ;
90
166
91
167
if (!head ) {
92
168
head = p ;
@@ -114,14 +190,14 @@ static void dlopen_js_onsuccess(struct dso* dso, struct async_data* data) {
114
190
dso -> mem_addr ,
115
191
dso -> mem_size );
116
192
load_library_done (dso );
117
- pthread_rwlock_unlock ( & lock );
193
+ do_unlock ( );
118
194
data -> onsuccess (data -> user_data , dso );
119
195
free (data );
120
196
}
121
197
122
198
static void dlopen_js_onerror (struct dso * dso , struct async_data * data ) {
123
199
dbg ("dlopen_js_onerror: dso=%p" , dso );
124
- pthread_rwlock_unlock ( & lock );
200
+ do_unlock ( );
125
201
data -> onerror (data -> user_data );
126
202
free (dso );
127
203
free (data );
@@ -134,7 +210,7 @@ static void ensure_init() {
134
210
return ;
135
211
}
136
212
// Initialize the dso list. This happens on first run.
137
- pthread_rwlock_wrlock ( & lock );
213
+ do_write_lock ( );
138
214
if (!head ) {
139
215
// Flags are not important since the main module is already loaded.
140
216
struct dso * p = load_library_start ("__main__" , RTLD_NOW |RTLD_GLOBAL );
@@ -143,7 +219,7 @@ static void ensure_init() {
143
219
load_library_done (p );
144
220
assert (head );
145
221
}
146
- pthread_rwlock_unlock ( & lock );
222
+ do_unlock ( );
147
223
}
148
224
149
225
void * dlopen (const char * file , int flags ) {
@@ -156,7 +232,11 @@ void* dlopen(const char* file, int flags) {
156
232
struct dso * p ;
157
233
int cs ;
158
234
pthread_setcancelstate (PTHREAD_CANCEL_DISABLE , & cs );
159
- pthread_rwlock_wrlock (& lock );
235
+ do_write_lock ();
236
+ #ifdef _REENTRANT
237
+ // Make sure we are in sync before loading any new DSOs.
238
+ dlsync_locked ();
239
+ #endif
160
240
161
241
/* Search for the name to see if it's already loaded */
162
242
for (p = head ; p ; p = p -> next ) {
@@ -180,7 +260,7 @@ void* dlopen(const char* file, int flags) {
180
260
dbg ("dlopen_js: success: %p" , p );
181
261
load_library_done (p );
182
262
end :
183
- pthread_rwlock_unlock ( & lock );
263
+ do_unlock ( );
184
264
pthread_setcancelstate (cs , 0 );
185
265
return p ;
186
266
}
@@ -192,10 +272,10 @@ void emscripten_dlopen(const char* filename, int flags, void* user_data,
192
272
onsuccess (user_data , head );
193
273
return ;
194
274
}
195
- pthread_rwlock_wrlock ( & lock );
275
+ do_write_lock ( );
196
276
struct dso * p = load_library_start (filename , flags );
197
277
if (!p ) {
198
- pthread_rwlock_unlock ( & lock );
278
+ do_unlock ( );
199
279
onerror (user_data );
200
280
return ;
201
281
}
@@ -217,9 +297,10 @@ void* __dlsym(void* restrict p, const char* restrict s, void* restrict ra) {
217
297
return 0 ;
218
298
}
219
299
void * res ;
220
- pthread_rwlock_rdlock ( & lock );
300
+ do_read_lock ( );
221
301
res = _dlsym_js (p , s );
222
- pthread_rwlock_unlock (& lock );
302
+ do_unlock ();
303
+ dbg ("__dlsym done dso:%p res:%p" , p , res );
223
304
return res ;
224
305
}
225
306
@@ -232,50 +313,3 @@ int dladdr(const void* addr, Dl_info* info) {
232
313
info -> dli_saddr = NULL ;
233
314
return 1 ;
234
315
}
235
-
236
- #ifdef _REENTRANT
237
- void _emscripten_thread_sync_code () {
238
- // This function is called from emscripten_yeild which itself is called
239
- // whenever we block on a futex. We need to check to avoid infinite
240
- // recursion when taking the lock below.
241
- static thread_local bool syncing = false;
242
- if (syncing ) {
243
- return ;
244
- }
245
- syncing = true;
246
- ensure_init ();
247
- if (thread_local_tail == tail ) {
248
- dbg ("emscripten_thread_sync_code: already in sync" );
249
- goto done ;
250
- }
251
- pthread_rwlock_rdlock (& lock );
252
- if (!thread_local_tail ) {
253
- thread_local_tail = head ;
254
- }
255
- while (thread_local_tail -> next ) {
256
- struct dso * p = thread_local_tail -> next ;
257
- dbg ("emscripten_thread_sync_code: %s mem_addr=%p "
258
- "mem_size=%zu table_addr=%p table_size=%zu" ,
259
- p -> name ,
260
- p -> mem_addr ,
261
- p -> mem_size ,
262
- p -> table_addr ,
263
- p -> table_size );
264
- void * success = _dlopen_js (p );
265
- if (!success ) {
266
- // If any on the libraries fails to load here then we give up.
267
- // TODO(sbc): Ideally this would never happen and we could/should
268
- // abort, but on the main thread (where we don't have sync xhr) its
269
- // often not possible to syncronously load side module.
270
- _emscripten_errf ("emscripten_thread_sync_code failed: %s" , dlerror ());
271
- break ;
272
- }
273
- thread_local_tail = p ;
274
- }
275
- pthread_rwlock_unlock (& lock );
276
- dbg ("emscripten_thread_sync_code done" );
277
-
278
- done :
279
- syncing = false;
280
- }
281
- #endif
0 commit comments