int uv_callback_init_ex(
uv_loop_t* loop,
uv_callback_t* callback,
uv_callback_func function,
int callback_type,
void (*free_cb)(void*),
void (*free_result)(void*)
){
int rc;
if (!loop || !callback || !function) return UV_EINVAL;
memset(callback, 0, sizeof(uv_callback_t));
callback->async.data = callback; /* mark as a uv_callback handle */
callback->function = function;
callback->refcount = 1;
callback->free_cb = free_cb;
switch(callback_type) {
case UV_DEFAULT:
callback->usequeue = 1;
callback->free_result = free_result;
callback->master = get_master_callback(loop);
if (callback->master) {
/* add this callback to the list */
uv_callback_t *base = callback->master;
while (base->next) { base = base->next; }
base->next = callback;
return 0; /* the uv_async handle is already initialized */
} else {
uv_mutex_init(&callback->mutex);
rc = uv_idle_init(loop, &callback->idle);
if (rc) return rc;
}
/* fallthrough */
case UV_COALESCE:
break;
default:
return UV_EINVAL;
}
return uv_async_init(loop, (uv_async_t*) callback, uv_callback_async_cb);
}
int uv_callback_init(uv_loop_t* loop, uv_callback_t* callback, uv_callback_func function, int callback_type) {
return uv_callback_init_ex(loop, callback, function, callback_type, NULL, NULL);
}
void uv_callback_stop(uv_callback_t* callback) {
if (!callback) return;
callback->inactive = 1;
if (callback->usequeue) {
dequeue_all_from_callback(callback->master, callback);
}
}
void stop_all_on_walk(uv_handle_t *handle, void *arg) {
if (uv_is_callback(handle)) {
uv_callback_t *callback = (uv_callback_t *) handle;
while (callback) {
uv_callback_t *next = callback->next;
uv_callback_stop(callback);
callback = next;
}
}
}
void uv_callback_stop_all(uv_loop_t* loop) {
uv_walk(loop, stop_all_on_walk, NULL);
}
/*****************************************************************************/
/* SENDER / CALLER THREAD ****************************************************/
/*****************************************************************************/
/* Asynchronous Callback Firing **********************************************/
int uv_callback_fire_ex(uv_callback_t* callback, void *data, int size, void (*free_data)(void*), uv_callback_t* notify) {
if (!callback) return UV_EINVAL;
if (callback->inactive) return UV_EPERM;
/* if there is a notification callback set, then the call must use a queue */
if (notify && !callback->usequeue) return UV_EINVAL;
if (callback->usequeue) {
/* allocate a new call info */
uv_call_t *call = malloc(sizeof(uv_call_t));
if (!call) return UV_ENOMEM;
/* save the call info */
call->data = data;
call->size = size;
call->notify = notify;
call->callback = callback;
call->free_data = free_data;
/* if there is a master callback, use it */
if (callback->master) callback = callback->master;
/* add the call to the queue */
uv_mutex_lock(&callback->mutex);
call->next = callback->queue;
callback->queue = call;
uv_mutex_unlock(&callback->mutex);
/* increase the reference counter */
if (notify) notify->refcount++;
} else {
callback->arg = data;
}
/* call uv_async_send */
return uv_async_send((uv_async_t*)callback);
}
int uv_callback_fire(uv_callback_t* callback, void *data, uv_callback_t* notify) {
return uv_callback_fire_ex(callback, data, 0, NULL, notify);
}
/* Synchronous Callback Firing ***********************************************/
struct call_result {
int timed_out;
int called;
void *data;
int size;
};
void callback_on_close(uv_handle_t *handle) {
if (uv_is_callback(handle)) {
uv_callback_release((uv_callback_t*) handle);
}
}
void callback_on_walk(uv_handle_t *handle, void *arg) {
uv_close(handle, callback_on_close);
}
void * on_call_result(uv_callback_t *callback, void *data, int size) {
uv_loop_t *loop = ((uv_handle_t*)callback)->loop;
struct call_result *result = loop->data;
result->called = 1;
result->data = data;
result->size = size;
uv_stop(loop);
return NULL;
}
void on_timer(uv_timer_t *timer) {
uv_loop_t *loop = timer->loop;
struct call_result *result = loop->data;
result->timed_out = 1;
uv_stop(loop);
}
int uv_callback_fire_sync(uv_callback_t* callback, void *data, void** presult, int timeout) {
struct call_result result = {0};