mirror of
https://github.com/curl/curl.git
synced 2026-08-25 23:23:31 +03:00
multi: add notifications API
Add infrastructure to colled and dispatch notifications for transfers and the multi handle in general. Applications can register a callback and en-/disable notification type the are interested in. Without a callback installed, notifications are not collected. Same when a notification type has not been enabled. Memory allocation failures on adding notifications lead to a general multi failure state and result in CURLM_OUT_OF_MEMORY returned from curl_multi_perform() and curl_multi_socket*() invocations. Closes #18432
This commit is contained in:
parent
f4e83a0adc
commit
357808f4ad
24 changed files with 767 additions and 44 deletions
63
lib/multi.c
63
lib/multi.c
|
|
@ -171,8 +171,15 @@ static void mstate(struct Curl_easy *data, CURLMstate state
|
|||
#endif
|
||||
|
||||
data->mstate = state;
|
||||
|
||||
if(state == MSTATE_COMPLETED) {
|
||||
switch(state) {
|
||||
case MSTATE_DONE:
|
||||
CURLM_NTFY(data, CURLM_NTFY_EASY_DONE);
|
||||
break;
|
||||
case MSTATE_COMPLETED:
|
||||
/* we sometimes directly jump to COMPLETED, trigger also a notification
|
||||
* in that case. */
|
||||
if(oldstate < MSTATE_DONE)
|
||||
CURLM_NTFY(data, CURLM_NTFY_EASY_DONE);
|
||||
/* changing to COMPLETED means it is in process and needs to go */
|
||||
DEBUGASSERT(Curl_uint_bset_contains(&data->multi->process, data->mid));
|
||||
Curl_uint_bset_remove(&data->multi->process, data->mid);
|
||||
|
|
@ -182,6 +189,9 @@ static void mstate(struct Curl_easy *data, CURLMstate state
|
|||
/* free the transfer buffer when we have no more active transfers */
|
||||
multi_xfer_bufs_free(data->multi);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/* if this state has an init-function, run it */
|
||||
|
|
@ -215,6 +225,8 @@ static void ph_freeentry(void *p)
|
|||
*/
|
||||
static void multi_addmsg(struct Curl_multi *multi, struct Curl_message *msg)
|
||||
{
|
||||
if(!Curl_llist_count(&multi->msglist))
|
||||
CURLM_NTFY(multi->admin, CURLM_NTFY_INFO_READ);
|
||||
Curl_llist_append(&multi->msglist, msg, &msg->list);
|
||||
}
|
||||
|
||||
|
|
@ -232,6 +244,7 @@ struct Curl_multi *Curl_multi_handle(unsigned int xfer_table_size,
|
|||
multi->magic = CURL_MULTI_HANDLE;
|
||||
|
||||
Curl_dnscache_init(&multi->dnscache, dnssize);
|
||||
Curl_mntfy_init(multi);
|
||||
Curl_multi_ev_init(multi, ev_hashsize);
|
||||
Curl_uint_tbl_init(&multi->xfers, NULL);
|
||||
Curl_uint_bset_init(&multi->process);
|
||||
|
|
@ -246,7 +259,8 @@ struct Curl_multi *Curl_multi_handle(unsigned int xfer_table_size,
|
|||
multi->max_concurrent_streams = 100;
|
||||
multi->last_timeout_ms = -1;
|
||||
|
||||
if(Curl_uint_bset_resize(&multi->process, xfer_table_size) ||
|
||||
if(Curl_mntfy_resize(multi) ||
|
||||
Curl_uint_bset_resize(&multi->process, xfer_table_size) ||
|
||||
Curl_uint_bset_resize(&multi->pending, xfer_table_size) ||
|
||||
Curl_uint_bset_resize(&multi->dirty, xfer_table_size) ||
|
||||
Curl_uint_bset_resize(&multi->msgsent, xfer_table_size) ||
|
||||
|
|
@ -305,6 +319,7 @@ error:
|
|||
multi->admin->multi = NULL;
|
||||
Curl_close(&multi->admin);
|
||||
}
|
||||
Curl_mntfy_cleanup(multi);
|
||||
|
||||
Curl_uint_bset_destroy(&multi->process);
|
||||
Curl_uint_bset_destroy(&multi->dirty);
|
||||
|
|
@ -2754,6 +2769,9 @@ CURLMcode curl_multi_perform(CURLM *m, int *running_handles)
|
|||
if(multi->in_callback)
|
||||
return CURLM_RECURSIVE_API_CALL;
|
||||
|
||||
if(multi->in_ntfy_callback)
|
||||
return CURLM_RECURSIVE_API_CALL;
|
||||
|
||||
sigpipe_init(&pipe_st);
|
||||
if(Curl_uint_bset_first(&multi->process, &mid)) {
|
||||
CURL_TRC_M(multi->admin, "multi_perform(running=%u)",
|
||||
|
|
@ -2785,6 +2803,9 @@ CURLMcode curl_multi_perform(CURLM *m, int *running_handles)
|
|||
if(multi_ischanged(m, TRUE))
|
||||
process_pending_handles(m);
|
||||
|
||||
if(!returncode)
|
||||
returncode = Curl_mntfy_dispatch_all(multi);
|
||||
|
||||
/*
|
||||
* Simply remove all expired timers from the splay since handles are dealt
|
||||
* with unconditionally by this function and curl_multi_timeout() requires
|
||||
|
|
@ -2831,6 +2852,8 @@ CURLMcode curl_multi_cleanup(CURLM *m)
|
|||
unsigned int mid;
|
||||
if(multi->in_callback)
|
||||
return CURLM_RECURSIVE_API_CALL;
|
||||
if(multi->in_ntfy_callback)
|
||||
return CURLM_RECURSIVE_API_CALL;
|
||||
|
||||
/* First remove all remaining easy handles,
|
||||
* close internal ones. admin handle is special */
|
||||
|
|
@ -2900,6 +2923,7 @@ CURLMcode curl_multi_cleanup(CURLM *m)
|
|||
#endif
|
||||
|
||||
multi_xfer_bufs_free(multi);
|
||||
Curl_mntfy_cleanup(multi);
|
||||
#ifdef DEBUGBUILD
|
||||
if(Curl_uint_tbl_count(&multi->xfers)) {
|
||||
multi_xfer_tbl_dump(multi);
|
||||
|
|
@ -3180,6 +3204,9 @@ out:
|
|||
if(multi_ischanged(multi, TRUE))
|
||||
process_pending_handles(multi);
|
||||
|
||||
if(!result)
|
||||
result = Curl_mntfy_dispatch_all(multi);
|
||||
|
||||
if(running_handles) {
|
||||
unsigned int running = Curl_multi_xfers_running(multi);
|
||||
*running_handles = (running < INT_MAX) ? (int)running : INT_MAX;
|
||||
|
|
@ -3269,6 +3296,12 @@ CURLMcode curl_multi_setopt(CURLM *m,
|
|||
}
|
||||
break;
|
||||
}
|
||||
case CURLMOPT_NOTIFYFUNCTION:
|
||||
multi->ntfy.ntfy_cb = va_arg(param, curl_notify_callback);
|
||||
break;
|
||||
case CURLMOPT_NOTIFYDATA:
|
||||
multi->ntfy.ntfy_cb_data = va_arg(param, void *);
|
||||
break;
|
||||
default:
|
||||
res = CURLM_UNKNOWN_OPTION;
|
||||
break;
|
||||
|
|
@ -3285,6 +3318,8 @@ CURLMcode curl_multi_socket(CURLM *m, curl_socket_t s, int *running_handles)
|
|||
struct Curl_multi *multi = m;
|
||||
if(multi->in_callback)
|
||||
return CURLM_RECURSIVE_API_CALL;
|
||||
if(multi->in_ntfy_callback)
|
||||
return CURLM_RECURSIVE_API_CALL;
|
||||
return multi_socket(multi, FALSE, s, 0, running_handles);
|
||||
}
|
||||
|
||||
|
|
@ -3294,6 +3329,8 @@ CURLMcode curl_multi_socket_action(CURLM *m, curl_socket_t s,
|
|||
struct Curl_multi *multi = m;
|
||||
if(multi->in_callback)
|
||||
return CURLM_RECURSIVE_API_CALL;
|
||||
if(multi->in_ntfy_callback)
|
||||
return CURLM_RECURSIVE_API_CALL;
|
||||
return multi_socket(multi, FALSE, s, ev_bitmask, running_handles);
|
||||
}
|
||||
|
||||
|
|
@ -3302,6 +3339,8 @@ CURLMcode curl_multi_socket_all(CURLM *m, int *running_handles)
|
|||
struct Curl_multi *multi = m;
|
||||
if(multi->in_callback)
|
||||
return CURLM_RECURSIVE_API_CALL;
|
||||
if(multi->in_ntfy_callback)
|
||||
return CURLM_RECURSIVE_API_CALL;
|
||||
return multi_socket(multi, TRUE, CURL_SOCKET_BAD, 0, running_handles);
|
||||
}
|
||||
|
||||
|
|
@ -3996,6 +4035,24 @@ void Curl_multi_clear_dirty(struct Curl_easy *data)
|
|||
Curl_uint_bset_remove(&data->multi->dirty, data->mid);
|
||||
}
|
||||
|
||||
CURLMcode curl_multi_notify_enable(CURLM *m, unsigned int notification)
|
||||
{
|
||||
struct Curl_multi *multi = m;
|
||||
|
||||
if(!GOOD_MULTI_HANDLE(multi))
|
||||
return CURLM_BAD_HANDLE;
|
||||
return Curl_mntfy_enable(multi, notification);
|
||||
}
|
||||
|
||||
CURLMcode curl_multi_notify_disable(CURLM *m, unsigned int notification)
|
||||
{
|
||||
struct Curl_multi *multi = m;
|
||||
|
||||
if(!GOOD_MULTI_HANDLE(multi))
|
||||
return CURLM_BAD_HANDLE;
|
||||
return Curl_mntfy_disable(multi, notification);
|
||||
}
|
||||
|
||||
#ifdef DEBUGBUILD
|
||||
static void multi_xfer_dump(struct Curl_multi *multi, unsigned int mid,
|
||||
void *entry)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue