static void process(ErlDrvData handle, ErlIOVec *ev) { spidermonkey_drv_t *dd = (spidermonkey_drv_t *) handle; char *data = ev->binv[1]->orig_bytes; char *command = read_command(&data); if (strncmp(command, "ij", 2) == 0) { char *call_id = read_string(&data); int thread_stack = read_int32(&data); if (thread_stack < 8) { thread_stack = 8; } thread_stack = thread_stack * (1024 * 1024); int heap_size = read_int32(&data) * (1024 * 1024); dd->vm = sm_initialize(thread_stack, heap_size); send_ok_response(dd, call_id); driver_free(call_id); } else { js_call *call_data = (js_call *) driver_alloc(sizeof(js_call)); call_data->driver_data = dd; call_data->args = ev->binv[1]; driver_binary_inc_refc(call_data->args); ErlDrvPort port = dd->port; unsigned long thread_key = (unsigned long) port; driver_async(dd->port, (unsigned int *) &thread_key, (asyncfun) run_js, (void *) call_data, NULL); } driver_free(command); }
static void standard_outputv(ErlDrvData drv_data, ErlIOVec* ev) { wxe_data* sd = (wxe_data *) drv_data; WXEBinRef * binref; ErlDrvBinary* bin; if(ev->vsize == 2) { binref = driver_alloc(sizeof(WXEBinRef)); binref->base = ev->iov[1].iov_base; binref->size = ev->iov[1].iov_len; binref->from = driver_caller(sd->port); bin = ev->binv[1]; driver_binary_inc_refc(bin); /* Otherwise it could get deallocated */ binref->bin = bin; binref->next = sd->bin; sd->bin = binref; } else { /* Empty binary (becomes NULL) */ binref = driver_alloc(sizeof(WXEBinRef)); binref->base = NULL; binref->size = 0; binref->from = driver_caller(sd->port); binref->bin = NULL; binref->next = sd->bin; sd->bin = binref; } }
static void av_decoder_schedule_decode(ErlDrvData drv_data, ErlIOVec *ev) { H264Decoder* d = (H264Decoder*)drv_data; // av_log(d->dec,AV_LOG_WARNING,"\nVSIZE:: %i\n"); ErlDrvBinary *h264 = NULL; int i; for(i = 0; i < ev->vsize; i++) { if(h264 && ev->binv[i]) { driver_failure_atom(d->port, "invalid_output_vector"); return; } if(ev->binv[i]) h264 = ev->binv[i]; } if(!h264) { driver_failure_atom(d->port, "invalid_output_vector"); return; } H264Frame *frame = driver_alloc(sizeof(H264Frame)); bzero(frame, sizeof(H264Frame)); frame->h264 = h264; // av_log(NULL,AV_LOG_INFO,"Size:: %i ",h264->orig_size); frame->decoder = d; driver_binary_inc_refc(h264); // I must change driver_free for other, more clever clearer, because yuv field must be also freed. driver_async(d->port, &d->key, av_async_decode, frame, driver_free); }
/* Put elements from vec at q head */ int erts_ioq_pushqv(ErtsIOQueue *q, ErtsIOVec* vec, Uint skipbytes) { int n; Uint len; Uint size = vec->common.size - skipbytes; SysIOVec* iov; ErtsIOQBinary** binv; ErtsIOQBinary* b; if (q == NULL) return -1; ASSERT(vec->common.size >= skipbytes); if (vec->common.size <= skipbytes) return 0; n = skip(vec, skipbytes, &iov, &binv, &len); if (n < 0) return n; if (q->v_head - n < q->v_start) if (expandq(q, n, 0)) return -1; /* Queue and reference all binaries (remove zero length items) */ iov += (n-1); /* move to end */ binv += (n-1); /* move to end */ while(n--) { if ((len = iov->iov_len) > 0) { if ((b = *binv) == NULL) { /* special case create binary ! */ if (q->driver) { ErlDrvBinary *bin = driver_alloc_binary(len); if (!bin) return -1; sys_memcpy(bin->orig_bytes, iov->iov_base, len); b = (ErtsIOQBinary *)bin; q->v_head->iov_base = bin->orig_bytes; } *--q->b_head = b; q->v_head--; q->v_head->iov_len = len; } else { if (q->driver) driver_binary_inc_refc(&b->driver); else erts_refc_inc(&b->nif.intern.refc, 1); *--q->b_head = b; *--q->v_head = *iov; } } iov--; binv--; } q->size += size; /* update total size in queue */ return 0; }
static void zmqdrv_send(zmq_drv_t *drv, ErlIOVec *ev) { ErlDrvBinary* bin = ev->binv[1]; char* bytes = bin->orig_bytes; uint32_t idx = ntohl(*(uint32_t*)(bytes+1)); zmq_sock_info* si = drv->get_socket_info(idx); uint32_t flags = ntohl(*(uint32_t*)(bytes+5)); void* data = (void *)(bytes + 9); size_t size = bin->orig_size - 9; if (idx > drv->zmq_socket_count || !si) { zmqdrv_error_code(drv, ENODEV); return; } #ifdef ZMQDRV_DEBUG uint32_t events; size_t events_size = sizeof(events); zmq_getsockopt(si->socket, ZMQ_EVENTS, &events, &events_size); zmqdrv_fprintf("sending %p [idx=%d] %lu bytes (events=%d)\r\n", si->socket, idx, size, events); #endif if (si->out_caller != 0) { // There's still an unwritten message pending zmqdrv_error_code(drv, EBUSY); return; } // Increment the reference count on binary so that zmq can // take ownership of it. driver_binary_inc_refc(bin); if (zmq_msg_init_data(&si->out_msg, data, size, &zmq_free_binary, bin)) { zmqdrv_error_code(drv, zmq_errno()); driver_binary_dec_refc(bin); return; } if (zmq_send(si->socket, &si->out_msg, flags | ZMQ_NOBLOCK) == 0) { zmqdrv_ok(drv); zmqdrv_ready_input((ErlDrvData)drv, (ErlDrvEvent)si->fd); } else { int e = zmq_errno(); if (e == EAGAIN) { // No msg returned to caller - make him wait until async // send succeeds si->out_caller = driver_caller(drv->port); return; } zmqdrv_error_code(drv, e); } zmq_msg_close(&si->out_msg); }
/* Put elements from vec at q tail */ int erts_ioq_enqv(ErtsIOQueue *q, ErtsIOVec *eiov, Uint skipbytes) { int n; Uint len; Uint size = eiov->common.size - skipbytes; SysIOVec *iov; ErtsIOQBinary** binv; ErtsIOQBinary* b; if (q == NULL) return -1; ASSERT(eiov->common.size >= skipbytes); if (eiov->common.size <= skipbytes) return 0; n = skip(eiov, skipbytes, &iov, &binv, &len); if (n < 0) return n; if (q->v_tail + n >= q->v_end) if (expandq(q, n, 1)) return -1; /* Queue and reference all binaries (remove zero length items) */ while(n--) { if ((len = iov->iov_len) > 0) { if ((b = *binv) == NULL) { /* special case create binary ! */ b = alloc_binary(len, iov->iov_base, (void**)&q->v_tail->iov_base, q->driver); if (!b) return -1; *q->b_tail++ = b; q->v_tail->iov_len = len; q->v_tail++; } else { if (q->driver) driver_binary_inc_refc(&b->driver); else erts_refc_inc(&b->nif.intern.refc, 1); *q->b_tail++ = b; *q->v_tail++ = *iov; } } iov++; binv++; } q->size += size; /* update total size in queue */ return 0; }
//-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~ static void wrap_zmq_send(zmq_drv_t *drv, const uint8_t* bytes, size_t size, ErlDrvBinary* bin) { int flags = *bytes; void* data = (void *)(bytes+sizeof(uint8_t)); size_t data_size = size - sizeof(uint8_t); assert(sizeof(uint8_t) <= size); ErlDrvTermData caller = driver_caller(drv->port); if (drv->terminating) { reply_error(drv->port, caller, ETERM); return; } zmq_sock_info* si = drv->get_socket_info(caller); if (!si) { reply_error(drv->port, caller, ENODEV); return; } assert(0 == si->out_caller); zmqdrv_fprintf("send %p (flags: %d bytes: %u)\r\n", si->socket, flags, data_size); // Increment the reference count on binary so that zmq can take ownership of it. driver_binary_inc_refc(bin); if (zmq_msg_init_data(&si->out_msg, data, data_size, &zmqcb_free_binary, bin)) { reply_error(drv->port, caller, zmq_errno()); driver_binary_dec_refc(bin); return; } if (0 == zmq_send(si->socket, &si->out_msg, flags|ZMQ_NOBLOCK)) { reply_ok(drv->port, caller); zmq_msg_close(&si->out_msg); } else if (ZMQ_NOBLOCK != (ZMQ_NOBLOCK & flags) && EAGAIN == zmq_errno()) { // Caller requested blocking send // Can't send right now. Make the caller wait by not returning result zmqdrv_fprintf("send %p blocking\r\n", si->socket); si->out_flags = flags; si->out_caller = caller; if (!si->busy) { driver_select(drv->port, si->fd, ERL_DRV_READ, 1); si->busy = true; } } else { reply_error(drv->port, caller, zmq_errno()); zmq_msg_close(&si->out_msg); } }
static void enm_outputv(ErlDrvData drv_data, ErlIOVec *ev) { EnmData* d = (EnmData*)drv_data; ErlIOVec qev; ErlDrvSizeT qtotal; struct nn_msghdr msghdr; int i, rc = -1, err; if (d->fd == -1 || d->protocol == NN_PULL || d->protocol == NN_SUB) return; qtotal = driver_peekqv(d->port, &qev); if (qtotal > 0) { memset(&msghdr, 0, sizeof msghdr); msghdr.msg_iov = (struct nn_iovec*)qev.iov; msghdr.msg_iovlen = qev.vsize; msghdr.msg_control = 0; err = 0; do { rc = enm_do_send(d, &msghdr, &err); if (rc < 0) { if (err == EAGAIN) { d->b.writable = 0; break; } else if (err != EINTR) { char errstr[32]; switch (enm_errno_str(err, errstr)) { case ENM_NANOMSG_ERROR: driver_failure_atom(d->port, errstr); break; case ENM_POSIX_ERROR: driver_failure_posix(d->port, err); break; case ENM_UNKNOWN_ERROR: driver_failure(d->port, err); break; } return; } } } while (err == EINTR); } /* * Do nothing if the message has no data */ if (ev->size == 0 || ev->vsize == 0 || (ev->vsize == 1 && *ev->binv == 0 && ev->iov->iov_len == 0)) return; if (d->b.writable) { memset(&msghdr, 0, sizeof msghdr); msghdr.msg_iov = (struct nn_iovec*)ev->iov; msghdr.msg_iovlen = ev->vsize; msghdr.msg_control = 0; err = 0; do { rc = enm_do_send(d, &msghdr, &err); if (rc < 0) { if (err == EAGAIN) { d->b.writable = 0; break; } else if (err != EINTR) { char errstr[32]; switch (enm_errno_str(err, errstr)) { case ENM_NANOMSG_ERROR: driver_failure_atom(d->port, errstr); break; case ENM_POSIX_ERROR: driver_failure_posix(d->port, err); break; case ENM_UNKNOWN_ERROR: driver_failure(d->port, err); break; } return; } } } while (err == EINTR); } if (rc < 0 && !d->b.writable) { rc = 0; d->b.busy = 1; set_busy_port(d->port, d->b.busy); for (i = 0; i < ev->vsize; i++) { ErlDrvBinary* bin = 0; if (ev->binv[i] != 0) { bin = ev->binv[i]; driver_binary_inc_refc(bin); } else if (ev->iov[i].iov_len > 0) { SysIOVec* vec = &ev->iov[i]; bin = driver_alloc_binary(vec->iov_len); memcpy(bin->orig_bytes, vec->iov_base, vec->iov_len); } if (bin != 0) driver_enq_bin(d->port, bin, 0, bin->orig_size); } if (!d->b.write_poll) enm_write_select(d, 1); } if (rc > 0 && d->protocol == NN_SURVEYOR && d->b.active != ENM_FALSE) enm_read_select(d, 1); }