@@ -47,6 +47,11 @@ void destroy_handle(CURL *cp) {
47
47
}
48
48
auto handle = iter->second ;
49
49
handle_buckets.erase (iter);
50
+
51
+ if (handle->easy_multi ) {
52
+ delete handle->easy_multi ;
53
+ }
54
+
50
55
delete handle;
51
56
swoole_trace_log (SW_TRACE_CO_CURL, SW_ECHO_RED " handle=%p, curl=%p" , " [DESTROY]" , handle, cp);
52
57
}
@@ -191,10 +196,6 @@ void Multi::set_event(CURL *cp, void *socket_ptr, curl_socket_t sockfd, int acti
191
196
}
192
197
193
198
CURLMcode Multi::add_handle (Handle *handle) {
194
- if (handle == nullptr ) {
195
- php_swoole_fatal_error (E_WARNING, " The given handle is not initialized in coroutine" );
196
- return CURLM_INTERNAL_ERROR;
197
- }
198
199
auto retval = curl_multi_add_handle (multi_handle_, handle->cp );
199
200
if (retval == CURLM_OK) {
200
201
handle->multi = this ;
@@ -242,21 +243,8 @@ CURLcode Multi::exec(Handle *handle) {
242
243
break ;
243
244
}
244
245
245
- int sockfd = last_sockfd;
246
- int bitmask = 0 ;
247
- if (sockfd >= 0 ) {
248
- auto it = handle->sockets .find (sockfd);
249
- if (it != handle->sockets .end ()) {
250
- curl_socket = it->second ;
251
- bitmask = curl_socket->event_bitmask ;
252
- if (!curl_socket->socket ->removed && swoole_event_del (curl_socket->socket ) == SW_OK) {
253
- event_count_--;
254
- }
255
- }
256
- }
257
- del_timer ();
246
+ selector_finish ();
258
247
259
- curl_multi_socket_action (multi_handle_, sockfd, bitmask, &running_handles_);
260
248
swoole_trace_log (SW_TRACE_CO_CURL,
261
249
" curl_multi_socket_action: handle=%p, sockfd=%d, bitmask=%d, running_handles_=%d" ,
262
250
handle,
@@ -267,38 +255,17 @@ CURLcode Multi::exec(Handle *handle) {
267
255
break ;
268
256
}
269
257
set_timer ();
270
- if (sockfd >= 0 ) {
271
- auto it = handle->sockets .find (sockfd);
272
- if (it != handle->sockets .end ()) {
273
- curl_socket = it->second ;
274
- if (curl_socket->socket && curl_socket->socket ->removed ) {
275
- if (swoole_event_add (curl_socket->socket , get_event (curl_socket->action )) == SW_OK) {
276
- event_count_++;
277
- }
278
- }
279
- }
280
- }
258
+ }
281
259
282
- if (!timer) {
283
- bool removed = true ;
284
- for (auto it = handle->sockets .begin (); it != handle->sockets .end ();) {
285
- curl_socket = it->second ;
286
- if (curl_socket->socket ) {
287
- if (curl_socket->socket ->removed ) {
288
- it = handle->sockets .erase (it);
289
- delete curl_socket;
290
- continue ;
291
- } else {
292
- removed = false ;
293
- }
294
- }
295
- ++it;
296
- }
297
- if (removed) {
298
- break ;
260
+ for (auto it : handle->sockets ) {
261
+ curl_socket = it.second ;
262
+ if (curl_socket->socket && !curl_socket->socket ->removed ) {
263
+ if (swoole_event_del (curl_socket->socket ) == SW_OK) {
264
+ event_count_--;
299
265
}
300
266
}
301
267
}
268
+ del_timer ();
302
269
303
270
CURLcode retval = read_info ();
304
271
remove_handle (handle);
@@ -347,6 +314,33 @@ int Multi::handle_timeout(CURLM *mh, long timeout_ms, void *userp) {
347
314
return 0 ;
348
315
}
349
316
317
+ void Multi::selector_finish () {
318
+ del_timer ();
319
+
320
+ if (selector.timer_callback ) {
321
+ selector.timer_callback = false ;
322
+ curl_multi_socket_action (multi_handle_, CURL_SOCKET_TIMEOUT, 0 , &running_handles_);
323
+ swoole_trace_log (SW_TRACE_CO_CURL, " socket_action[timer], running_handles=%d" , running_handles_);
324
+ }
325
+
326
+ for (auto handle : selector.active_handles ) {
327
+ /* *
328
+ * In `curl_multi_socket_action`, `Handle::destroy_socket()` may be invoked,
329
+ * which will remove entries from the `unordered_map`.
330
+ * In C++, removing elements during iteration can render the iterator invalid; hence,
331
+ * it's necessary to copy `handle->sockets` into a new `unordered_map`.
332
+ */
333
+ auto sockets = handle->sockets ;
334
+ for (auto it : sockets) {
335
+ HandleSocket *handle_socket = it.second ;
336
+ curl_multi_socket_action (
337
+ multi_handle_, handle_socket->event_fd , handle_socket->event_bitmask , &running_handles_);
338
+ swoole_trace_log (SW_TRACE_CO_CURL, " socket_action[socket], running_handles=%d" , running_handles_);
339
+ }
340
+ }
341
+ selector.active_handles .clear ();
342
+ }
343
+
350
344
long Multi::select (php_curlm *mh, double timeout) {
351
345
if (zend_llist_count (&mh->easyh ) == 0 ) {
352
346
return 0 ;
@@ -399,7 +393,7 @@ long Multi::select(php_curlm *mh, double timeout) {
399
393
400
394
swoole_trace_log (SW_TRACE_CO_CURL, " yield timeout, count=%lu" , zend_llist_count (&mh->easyh ));
401
395
402
- auto count = selector-> active_handles .size ();
396
+ auto count = selector. active_handles .size ();
403
397
404
398
for (zend_llist_element *element = mh->easyh .head ; element; element = element->next ) {
405
399
zval *z_ch = (zval *) element->data ;
@@ -419,44 +413,17 @@ long Multi::select(php_curlm *mh, double timeout) {
419
413
}
420
414
}
421
415
}
422
- del_timer ();
423
416
424
- if (selector->timer_callback ) {
425
- selector->timer_callback = false ;
426
- curl_multi_socket_action (multi_handle_, CURL_SOCKET_TIMEOUT, 0 , &running_handles_);
427
- swoole_trace_log (SW_TRACE_CO_CURL, " socket_action[timer], running_handles=%d" , running_handles_);
428
- }
429
-
430
- for (auto iter = selector->active_handles .begin (); iter != selector->active_handles .end (); iter++) {
431
- Handle *handle = *iter;
432
- if (handle) {
433
- for (auto it = handle->sockets .begin (); it != handle->sockets .end ();) {
434
- HandleSocket *handle_socket = it->second ;
435
- it++;
436
- curl_multi_socket_action (
437
- multi_handle_, handle_socket->event_fd , handle_socket->event_bitmask , &running_handles_);
438
- swoole_trace_log (SW_TRACE_CO_CURL, " socket_action[socket], running_handles=%d" , running_handles_);
439
- }
440
- }
441
- }
442
-
443
- selector->active_handles .clear ();
417
+ selector_finish ();
444
418
445
419
return count;
446
420
}
447
421
448
422
void Multi::callback (Handle *handle, int event_bitmask, int sockfd) {
449
423
swoole_trace_log (
450
424
SW_TRACE_CO_CURL, " handle=%p, event_bitmask=%d, co=%p, sockfd=%d" , handle, event_bitmask, co, sockfd);
451
- if (handle) {
452
- last_sockfd = sockfd;
453
- } else {
454
- last_sockfd = -1 ;
455
- }
456
- if (selector.get ()) {
457
- if (!handle) {
458
- selector->timer_callback = true ;
459
- }
425
+ if (!handle) {
426
+ selector.timer_callback = true ;
460
427
}
461
428
if (!co) {
462
429
if (handle) {
@@ -470,8 +437,8 @@ void Multi::callback(Handle *handle, int event_bitmask, int sockfd) {
470
437
}
471
438
return ;
472
439
}
473
- if (selector. get () && handle) {
474
- selector-> active_handles .insert (handle);
440
+ if (handle) {
441
+ selector. active_handles .insert (handle);
475
442
}
476
443
if (defer_callback) {
477
444
return ;
@@ -490,10 +457,11 @@ void Multi::callback(Handle *handle, int event_bitmask, int sockfd) {
490
457
} // namespace swoole
491
458
492
459
CURLcode swoole_curl_easy_perform (CURL *cp) {
493
- Multi *multi = new Multi ();
494
- CURLcode error = multi->exec (swoole::curl::get_handle (cp));
495
- delete multi;
496
- return error;
460
+ auto handle = swoole::curl::get_handle (cp);
461
+ if (!handle->easy_multi ) {
462
+ handle->easy_multi = new Multi ();
463
+ }
464
+ return handle->easy_multi ->exec (handle);
497
465
}
498
466
499
467
php_curl *swoole_curl_get_handle (zval *zid, bool exclusive, bool required) {
@@ -503,6 +471,10 @@ php_curl *swoole_curl_get_handle(zval *zid, bool exclusive, bool required) {
503
471
}
504
472
if (exclusive && swoole_coroutine_is_in ()) {
505
473
auto handle = swoole::curl::get_handle (ch->cp );
474
+ if (required && !handle) {
475
+ php_swoole_fatal_error (E_WARNING, " The given handle is not initialized in coroutine" );
476
+ return nullptr ;
477
+ }
506
478
if (handle && handle->multi && handle->multi ->check_bound_co () == nullptr ) {
507
479
return nullptr ;
508
480
}
0 commit comments