EV-Gearman
view release on metacpan or search on metacpan
src/EV__Gearman.xs view on Meta::CPAN
len, (unsigned)GM_MAX_PACKET);
}
static void send_pending_waits(pTHX_ ev_gm_t *self) {
while (!ngx_queue_empty(&self->wait_queue) && self->connected) {
ngx_queue_t *q = ngx_queue_head(&self->wait_queue);
ev_gm_wait_t *w = ngx_queue_data(q, ev_gm_wait_t, queue);
ngx_queue_remove(q);
self->waiting_count--;
buf_append_write(self, w->packet, w->packet_len);
if (w->req) {
ngx_queue_insert_tail(&self->cb_queue, &w->req->queue);
self->pending_count++;
w->req = NULL;
arm_cmd_timer(self);
}
Safefree(w->packet); w->packet = NULL;
Safefree(w);
start_writing(self);
}
}
/* ================================================================
* Worker helpers (state machine for GRAB / NOOP / PRE_SLEEP)
* ================================================================ */
static ev_gm_func_t* find_function(ev_gm_t *self, const char *name, STRLEN len) {
ngx_queue_t *q;
for (q = ngx_queue_head(&self->functions); q != ngx_queue_sentinel(&self->functions);
q = ngx_queue_next(q))
{
ev_gm_func_t *f = ngx_queue_data(q, ev_gm_func_t, queue);
if (strlen(f->name) == len && memcmp(f->name, name, len) == 0)
return f;
}
return NULL;
}
static void worker_send_grab(pTHX_ ev_gm_t *self) {
if (!self->connected) return;
if (self->worker_grab_inflight) return;
if (ngx_queue_empty(&self->functions)) return;
self->worker_grab_inflight = 1;
ev_gm_req_t *r = alloc_req(CB_GRAB_JOB, NULL);
enqueue_packet(aTHX_ self,
self->worker_grab_uniq ? GM_CMD_GRAB_JOB_UNIQ : GM_CMD_GRAB_JOB,
NULL, 0, r);
}
static void worker_send_pre_sleep(pTHX_ ev_gm_t *self) {
if (!self->connected) return;
if (self->worker_sleeping) return;
self->worker_sleeping = 1;
enqueue_packet(aTHX_ self, GM_CMD_PRE_SLEEP, NULL, 0, NULL);
}
/* Drive the worker loop forward: if active and not busy, GRAB. */
static void worker_continue(pTHX_ ev_gm_t *self) {
if (!self->worker_active || !self->connected) return;
if (self->worker_grab_inflight || self->worker_sleeping) return;
if (ngx_queue_empty(&self->functions)) return;
worker_send_grab(aTHX_ self);
}
/* ================================================================
* Connect-success path: re-register worker functions, drain queue
* ================================================================ */
/* Send a WORK_* packet whose body is "handle" + optional "\0data".
For WORK_FAIL pass dp=NULL; otherwise pass payload bytes. */
static void send_work_event(pTHX_ ev_gm_t *self, uint32_t cmd,
const char *h, STRLEN hl, const char *dp, STRLEN dl)
{
/* No size croak here: this runs on the worker completion / event
path (worker_dispatch_job, $job->complete), where a longjmp would
unwind the EV loop mid-iteration. A >4 GiB result is not a real
concern (the worker would OOM building it first). */
size_t plen = dp ? hl + 1 + dl : hl;
char *body;
Newx(body, plen ? plen : 1, char);
memcpy(body, h, hl);
if (dp) {
body[hl] = '\0';
if (dl) memcpy(body + hl + 1, dp, dl);
}
enqueue_packet(aTHX_ self, cmd, body, plen, NULL);
Safefree(body);
}
/* Send CAN_DO[_TIMEOUT] for one function name. Builds the
"name\0timeout" body on the heap to avoid the 512-byte stack-buffer
truncation that the older inline pattern was prone to. */
static void send_can_do(pTHX_ ev_gm_t *self,
const char *name, STRLEN nlen, int timeout)
{
if (!self->connected) return;
if (timeout > 0) {
char tbuf[16];
int tlen = snprintf(tbuf, sizeof(tbuf), "%d", timeout);
if (tlen <= 0) return;
size_t plen = nlen + 1 + (size_t)tlen;
char *body;
Newx(body, plen, char);
memcpy(body, name, nlen);
body[nlen] = '\0';
memcpy(body + nlen + 1, tbuf, tlen);
enqueue_packet(aTHX_ self, GM_CMD_CAN_DO_TIMEOUT, body, plen, NULL);
Safefree(body);
} else {
enqueue_packet(aTHX_ self, GM_CMD_CAN_DO, name, nlen, NULL);
}
}
static void register_all_functions(pTHX_ ev_gm_t *self) {
if (!self->connected) return;
ngx_queue_t *q;
for (q = ngx_queue_head(&self->functions); q != ngx_queue_sentinel(&self->functions);
( run in 0.624 second using v1.01-cache-2.11-cpan-600a1bdf6e4 )