@@ -73,74 +73,23 @@ struct resdata {
73
73
struct curltime start ;
74
74
};
75
75
76
- /* Doubly linked list of orphaned thread handles. */
77
- struct thread_list {
78
- curl_thread_t handle ;
79
-
80
- /* 'exiting' is set true right before an orphaned thread exits.
81
- it should only be set by the orphaned thread from
82
- signal_orphan_is_exiting(). */
83
- bool exiting ;
84
-
85
- struct thread_list * prev , * next ;
86
- };
87
-
88
- /* Orphaned threads: A global list of resolver threads that could not be
89
- * completed in time and so they were abandoned by their parent. The list is
90
- * culled periodically by soon-to-be exiting orphans to wait on and destroy
91
- * those that are in the process of or have since exited, which is fast. On
92
- * global cleanup we wait on and destroy any remaining threads, which may be
93
- * slow but at that point we cannot defer it any longer.
94
- */
95
- struct orphaned_threads {
96
- /* Mutex to lock this. To avoid deadlock the thread-specific thread_sync_data
97
- mutex cannot be used as an inner lock when orphaned_threads is locked. */
98
- curl_mutex_t mutex ;
99
-
100
- /* List of orphaned threads. */
101
- struct thread_list * first , * last ;
102
-
103
- /* Count of threads in the list that are in the process of or have exited.
104
- (ie .exiting member of the thread_list item is set true) */
105
- size_t exiting_count ;
106
- };
107
-
108
- static struct orphaned_threads orphaned_threads ;
109
-
110
- /* Flags for wait_and_destroy_orphaned_threads().
111
- They're documented above the function definition. */
112
- #define WAIT_DESTROY_ALL (1<<0)
113
- #define WAIT_DESTROY_EXITING_THREADS_ONLY (1<<1)
114
-
115
- static void wait_and_destroy_orphaned_threads (int flags );
116
- static void signal_orphan_is_exiting (struct thread_list * orphan );
117
-
118
-
119
76
/*
120
77
* Curl_resolver_global_init()
121
78
* Called from curl_global_init() to initialize global resolver environment.
79
+ * Does nothing here.
122
80
*/
123
81
int Curl_resolver_global_init (void )
124
82
{
125
- memset (& orphaned_threads , 0 , sizeof (orphaned_threads ));
126
-
127
- if (Curl_mutex_init (& orphaned_threads .mutex ))
128
- return CURLE_FAILED_INIT ;
129
-
130
83
return CURLE_OK ;
131
84
}
132
85
133
86
/*
134
87
* Curl_resolver_global_cleanup()
135
88
* Called from curl_global_cleanup() to destroy global resolver environment.
89
+ * Does nothing here.
136
90
*/
137
91
void Curl_resolver_global_cleanup (void )
138
92
{
139
- /* Take ownership of all orphaned resolver threads and wait for them to exit.
140
- This is necessary because the user may choose to unload the shared library
141
- that is/contains libcurl. */
142
- wait_and_destroy_orphaned_threads (WAIT_DESTROY_ALL );
143
- Curl_mutex_destroy (& orphaned_threads .mutex );
144
93
}
145
94
146
95
/*
@@ -220,8 +169,6 @@ struct thread_data {
220
169
unsigned int poll_interval ;
221
170
timediff_t interval_end ;
222
171
struct thread_sync_data tsd ;
223
- /* 'reserved' memory must be available in case the thread is orphaned */
224
- void * reserved ;
225
172
};
226
173
227
174
static struct thread_sync_data * conn_thread_sync_data (struct Curl_easy * data )
@@ -283,11 +230,7 @@ int init_thread_sync_data(struct thread_data *td,
283
230
if (!tsd -> mtx )
284
231
goto err_exit ;
285
232
286
- if (Curl_mutex_init (tsd -> mtx )) {
287
- free (tsd -> mtx );
288
- tsd -> mtx = NULL ;
289
- goto err_exit ;
290
- }
233
+ Curl_mutex_init (tsd -> mtx );
291
234
292
235
#ifndef CURL_DISABLE_SOCKETPAIR
293
236
/* create socket pair or pipe */
@@ -346,7 +289,6 @@ static unsigned int CURL_STDCALL getaddrinfo_thread(void *arg)
346
289
{
347
290
struct thread_sync_data * tsd = (struct thread_sync_data * )arg ;
348
291
struct thread_data * td = tsd -> td ;
349
- struct thread_list * orphan = NULL ;
350
292
char service [12 ];
351
293
int rc ;
352
294
#ifndef CURL_DISABLE_SOCKETPAIR
@@ -371,7 +313,6 @@ static unsigned int CURL_STDCALL getaddrinfo_thread(void *arg)
371
313
/* too late, gotta clean up the mess */
372
314
Curl_mutex_release (tsd -> mtx );
373
315
destroy_thread_sync_data (tsd );
374
- orphan = (struct thread_list * )td -> reserved ;
375
316
free (td );
376
317
}
377
318
else {
@@ -389,9 +330,6 @@ static unsigned int CURL_STDCALL getaddrinfo_thread(void *arg)
389
330
Curl_mutex_release (tsd -> mtx );
390
331
}
391
332
392
- if (orphan )
393
- signal_orphan_is_exiting (orphan );
394
-
395
333
return 0 ;
396
334
}
397
335
@@ -404,7 +342,6 @@ static unsigned int CURL_STDCALL gethostbyname_thread(void *arg)
404
342
{
405
343
struct thread_sync_data * tsd = (struct thread_sync_data * )arg ;
406
344
struct thread_data * td = tsd -> td ;
407
- struct thread_list * orphan = NULL ;
408
345
409
346
tsd -> res = Curl_ipv4_resolve_r (tsd -> hostname , tsd -> port );
410
347
@@ -419,17 +356,13 @@ static unsigned int CURL_STDCALL gethostbyname_thread(void *arg)
419
356
/* too late, gotta clean up the mess */
420
357
Curl_mutex_release (tsd -> mtx );
421
358
destroy_thread_sync_data (tsd );
422
- orphan = (struct thread_list * )td -> reserved ;
423
359
free (td );
424
360
}
425
361
else {
426
362
tsd -> done = 1 ;
427
363
Curl_mutex_release (tsd -> mtx );
428
364
}
429
365
430
- if (orphan )
431
- signal_orphan_is_exiting (orphan );
432
-
433
366
return 0 ;
434
367
}
435
368
@@ -448,60 +381,25 @@ static void destroy_async_data(struct Curl_async *async)
448
381
struct Curl_easy * data = td -> tsd .data ;
449
382
#endif
450
383
451
- /* We can't wait any longer for the resolver thread so if it's not done
452
- * then it must be orphaned.
453
- *
454
- * 1) add thread to orphaned threads list
455
- * 2) set thread done (this signals to thread it has been orphaned)
456
- *
457
- * An orphaned thread does most of its own cleanup, and any remaining
458
- * cleanup is handled during global cleanup.
384
+ /*
385
+ * if the thread is still blocking in the resolve syscall, detach it and
386
+ * let the thread do the cleanup...
459
387
*/
460
-
461
388
Curl_mutex_acquire (td -> tsd .mtx );
462
-
463
- if (!td -> tsd .done && td -> thread_hnd != curl_thread_t_null ) {
464
- struct thread_list * orphan = (struct thread_list * )td -> reserved ;
465
-
466
- Curl_mutex_acquire (& orphaned_threads .mutex );
467
-
468
- #ifdef DEBUGBUILD
469
- {
470
- struct thread_list empty ;
471
- memset (& empty , 0 , sizeof (empty ));
472
- DEBUGASSERT (!memcmp (& empty , orphan , sizeof (empty )));
473
- }
474
- #endif
475
-
476
- orphan -> handle = td -> thread_hnd ;
477
- orphan -> exiting = false;
478
-
479
- if (orphaned_threads .last ) {
480
- orphaned_threads .last -> next = orphan ;
481
- orphan -> prev = orphaned_threads .last ;
482
- }
483
- else {
484
- orphaned_threads .first = orphan ;
485
- orphan -> prev = NULL ;
486
- }
487
- orphaned_threads .last = orphan ;
488
- orphan -> next = NULL ;
489
-
490
- Curl_mutex_release (& orphaned_threads .mutex );
491
- }
492
-
493
389
done = td -> tsd .done ;
494
390
td -> tsd .done = 1 ;
495
-
496
391
Curl_mutex_release (td -> tsd .mtx );
497
392
498
- if (done ) {
393
+ if (!done ) {
394
+ Curl_thread_destroy (td -> thread_hnd );
395
+ }
396
+ else {
499
397
if (td -> thread_hnd != curl_thread_t_null )
500
398
Curl_thread_join (& td -> thread_hnd );
501
399
502
400
destroy_thread_sync_data (& td -> tsd );
503
- free ( td -> reserved );
504
- free (td );
401
+
402
+ free (async -> tdata );
505
403
}
506
404
#ifndef CURL_DISABLE_SOCKETPAIR
507
405
/*
@@ -541,11 +439,9 @@ static bool init_resolve_thread(struct Curl_easy *data,
541
439
asp -> status = 0 ;
542
440
asp -> dns = NULL ;
543
441
td -> thread_hnd = curl_thread_t_null ;
544
- td -> reserved = calloc (1 , sizeof (struct thread_list ));
545
442
546
- if (!td -> reserved || ! init_thread_sync_data (td , hostname , port , hints )) {
443
+ if (!init_thread_sync_data (td , hostname , port , hints )) {
547
444
asp -> tdata = NULL ;
548
- free (td -> reserved );
549
445
free (td );
550
446
goto errno_exit ;
551
447
}
@@ -564,7 +460,7 @@ static bool init_resolve_thread(struct Curl_easy *data,
564
460
td -> thread_hnd = Curl_thread_create (gethostbyname_thread , & td -> tsd );
565
461
#endif
566
462
567
- if (td -> thread_hnd == curl_thread_t_null ) {
463
+ if (! td -> thread_hnd ) {
568
464
/* The thread never started, so mark it as done here for proper cleanup. */
569
465
td -> tsd .done = 1 ;
570
466
err = errno ;
@@ -861,100 +757,4 @@ CURLcode Curl_set_dns_local_ip6(struct Curl_easy *data,
861
757
return CURLE_NOT_BUILT_IN ;
862
758
}
863
759
864
- /* Helper function to wait and destroy some or all orphaned threads.
865
- *
866
- * WAIT_DESTROY_ALL:
867
- * Wait and destroy all orphaned threads. This operation is not safe to specify
868
- * in code that could run in any thread that may be orphaned (ie any resolver
869
- * thread). Waiting on all orphaned threads may take some time. This operation
870
- * must be specified in the call from global cleanup, and ideally nowhere else.
871
- *
872
- * WAIT_DESTROY_EXITING_THREADS_ONLY:
873
- * Wait and destroy only orphaned threads that are in the process of or have
874
- * since exited (ie those with .exiting set true). This is fast.
875
- *
876
- * When the calling thread owns orphaned_threads.mutex it must not call this
877
- * function or deadlock my occur.
878
- */
879
- static void wait_and_destroy_orphaned_threads (int flags )
880
- {
881
- struct thread_list * thread = NULL ;
882
-
883
- Curl_mutex_acquire (& orphaned_threads .mutex );
884
-
885
- if ((flags & WAIT_DESTROY_EXITING_THREADS_ONLY )) {
886
- struct thread_list * p , * next ;
887
- struct thread_list * first = NULL , * last = NULL ;
888
-
889
- if (!orphaned_threads .exiting_count ) {
890
- Curl_mutex_release (& orphaned_threads .mutex );
891
- return ;
892
- }
893
-
894
- for (p = orphaned_threads .first ; p ; p = next ) {
895
- next = p -> next ;
896
-
897
- if (!p -> exiting )
898
- continue ;
899
-
900
- /* remove thread list item from orphaned_threads */
901
- if (p -> prev )
902
- p -> prev -> next = p -> next ;
903
- if (p -> next )
904
- p -> next -> prev = p -> prev ;
905
- if (orphaned_threads .first == p )
906
- orphaned_threads .first = p -> next ;
907
- if (orphaned_threads .last == p )
908
- orphaned_threads .last = p -> prev ;
909
-
910
- /* add thread list item to new thread list */
911
- if (last ) {
912
- last -> next = p ;
913
- p -> prev = last ;
914
- }
915
- else {
916
- first = p ;
917
- p -> prev = NULL ;
918
- }
919
- last = p ;
920
- p -> next = NULL ;
921
- }
922
-
923
- thread = first ;
924
- orphaned_threads .exiting_count = 0 ;
925
- }
926
- else if ((flags & WAIT_DESTROY_ALL )) {
927
- thread = orphaned_threads .first ;
928
- orphaned_threads .first = NULL ;
929
- orphaned_threads .last = NULL ;
930
- orphaned_threads .exiting_count = 0 ;
931
- }
932
-
933
- Curl_mutex_release (& orphaned_threads .mutex );
934
-
935
- /* Wait and free. Must be done unlocked or there could be deadlock. */
936
- while (thread ) {
937
- struct thread_list * next = thread -> next ;
938
- Curl_thread_join (& thread -> handle );
939
- free (thread );
940
- thread = next ;
941
- }
942
- }
943
-
944
- /* Helper function that must be called from an orphaned thread right before it
945
- exits. */
946
- static void signal_orphan_is_exiting (struct thread_list * orphan )
947
- {
948
- DEBUGASSERT (orphan -> handle && !orphan -> exiting );
949
-
950
- wait_and_destroy_orphaned_threads (WAIT_DESTROY_EXITING_THREADS_ONLY );
951
-
952
- Curl_mutex_acquire (& orphaned_threads .mutex );
953
-
954
- orphan -> exiting = true;
955
- orphaned_threads .exiting_count ++ ;
956
-
957
- Curl_mutex_release (& orphaned_threads .mutex );
958
- }
959
-
960
760
#endif /* CURLRES_THREADED */
0 commit comments