static void output(ErlDrvData drv_data, char *buf, ErlDrvSizeT len) { Otp9302Data *data = (Otp9302Data *) drv_data; ErlDrvTermData td_port = driver_mk_port(data->port); ErlDrvTermData td_receiver = driver_caller(data->port); ErlDrvTermData td_job = driver_mk_atom("job"); unsigned int key = (unsigned int) (ErlDrvSInt) data->port; long id[5]; Otp9302AsyncData *ad[5]; int i; for (i = 0; i < sizeof(ad)/sizeof(ad[0]); i++) { ad[i] = driver_alloc(sizeof(Otp9302AsyncData)); if (!ad[i]) abort(); ad[i]->smp = data->smp; ad[i]->port = data->port; ad[i]->block = 0; ad[i]->refc = 1; ad[i]->term_data.port = td_port; ad[i]->term_data.receiver = td_receiver; ad[i]->term_data.msg = td_job; ad[i]->msgq = &data->msgq; } ad[0]->block = 1; ad[0]->term_data.msg = driver_mk_atom("block"); ad[2]->term_data.msg = driver_mk_atom("cancel"); ad[4]->term_data.msg = driver_mk_atom("end_of_jobs"); for (i = 0; i < sizeof(id)/sizeof(id[0]); i++) id[i] = driver_async(data->port, &key, async_invoke, ad[i], driver_free); if (id[2] > 0) driver_async_cancel(id[2]); }
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 tcbdb_output (ErlDrvData handle, char* buf, int buflen) { TcDriverData* d = (TcDriverData*) handle; FromEmulator from = decode_from (d, buf, buflen); switch (from.type) { case EMULATOR_REQUEST_INVALID: reply_string (d->port, driver_caller (d->port), "invalid request"); break; default: driver_async (d->port, &d->magic, async_invoke, from_emulator_dup (&from), async_free); break; } }
PRIVATESTUFF int exp1_read(descriptor *d, char *buf, int buflen) { char cmd; struct t_data *td = sys_alloc(sizeof(struct t_data)); assert(td != NULL); assert(buflen >= 4); cmd = *buf++; td->cmd = cmd; td->id = get_int32(buf); buf += 4; td->name = NULL; fprintf(DEBUGIO, "exp1_read: cmd = %d, id = %ld\r\n", cmd, td->id); switch (cmd) { case EXP1_REQ_GETHOSTBYNAME: /* buf = null-terminated hostname */ /* XXX use something other than strdup()? */ td->name = strdup(buf); driver_async(d->port, KEY, invoke_gethostbyname, (void *) td, free_t_data); break; } /* ** XXX I guess we'll ignore everything else, let the caller hang. */ fprintf(DEBUGIO, "exp1_read: done\r\n"); return 0; }
static void gen_q_drv_output(ErlDrvData handle, char *buff, ErlDrvSizeT bufflen) { GenQData *d = (GenQData*)handle; QWork* work = genq_alloc_work(buff, bufflen); if(work->op == FUNC_OPTS) { LOG("received opts %ld\n", work->op); copy_qopts((QOpts*)work->data, &d->opts); genq_free_work(work); LOG("responding %s\n", "ok"); ei_x_buff ok; ei_x_new(&ok); ei_x_encode_ok(&ok); driver_output(d->port, ok.buff, ok.index); ei_x_free(&ok); return; } else if(work->data == NULL) { genq_free_work(work); ei_x_buff error; ei_x_new(&error); ei_x_encode_error_tuple_atom(&error, "badarg"); driver_output(d->port, error.buff, error.index); ei_x_free(&error); return; } work->opts = &d->opts; driver_async(d->port, work->dispatch_key, genq_work, work, genq_free_work); }
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); }
static void output(ErlDrvData handle, char *buff, int len) { Gd *gd = (Gd*)handle; char cmd = buff[0]; char *data = &buff[1]; int size = len-1; asyncFun function; Cmd *command = driver_alloc(sizeof(Cmd) + size); command->gd = gd; command->size = size; memcpy(command->data, data, size); switch(cmd) { case SIZE: function = get_size; break; case READ: function = read_image; break; case RESIZE: function = resize; break; case BLOB: function = get_blob; break; case CROP: function = crop; break; } //function(command); //driver_free(command); driver_async(gd->port, NULL, function, command, driver_free); }
int main() { int i; init_async(); for (i = 0; i < 30; i++) { AsyncData* d = (AsyncData*) malloc(sizeof (AsyncData)); d->key = i; d->value = i; int c = i; driver_async((unsigned int*) & c, io_test, d, NULL); } printf("the result\n"); pthread_t main_thread = pthread_self(); pthread_exit(&main_thread); return 0; }
static void output(ErlDrvData drv_data, char *buf, ErlDrvSizeT len) { async_blast_data_t *abd = (async_blast_data_t *) drv_data; if (abd->counter == 0) { int i; abd->caller = driver_caller(abd->port); abd->counter = NO_ASYNC_JOBS; for (i = 0; i < NO_ASYNC_JOBS; i++) { if (0 > driver_async(abd->port, NULL, async_invoke, NULL, NULL)) { driver_failure_atom(abd->port, "driver_async_failed"); break; } } } }
static void test_drv_output(ErlDrvData handle, char *buff, ErlDrvSizeT bufflen) { test_data* d = (test_data*)handle; test_async_data* ad = (test_async_data*)driver_alloc(sizeof(test_async_data)); char method = buff[0], fn = buff[1], arg = buff[2], res; switch (method) { case 1: res = (char) do_f(fn, arg); driver_output(d->port, &res, 1); break; case 2: ad->fn = fn; ad->arg = arg; driver_async(d->port, NULL, do_async, (void *) ad, NULL); } }
static int sql_exec_script(sqlite3_drv_t *drv, char *command, int command_size) { async_sqlite3_command *async_command = make_async_command_script(drv, command, command_size); #ifdef DEBUG fprintf(drv->log, "Driver async: %d %p\n", SQLITE_VERSION_NUMBER, async_command->statement); fflush(drv->log); #endif if (sqlite3_threadsafe()) { drv->async_handle = driver_async(drv->port, &drv->key, sql_exec_async, async_command, sql_free_async); } else { sql_exec_async(async_command); ready_async((ErlDrvData) drv, (ErlDrvThreadData) async_command); } return 0; }
static void test_drv_outputv(ErlDrvData handle, ErlIOVec *ev) { test_data* d = (test_data*)handle; test_async_data* ad = (test_async_data*)driver_alloc(sizeof(test_async_data)); size_t p, q; char method, fn, arg, res; p = 0; q = 1; EV_GET_CHAR(ev, &method, &p, &q); EV_GET_CHAR(ev, &fn, &p, &q); EV_GET_CHAR(ev, &arg, &p, &q); switch (method) { case 1: res = (char) do_f(fn, arg); driver_output(d->port, &res, 1); break; case 2: ad->fn = fn; ad->arg = arg; driver_async(d->port, NULL, do_async, (void *) ad, NULL); } }
static void tcbdb_stop (ErlDrvData handle) { TcDriverData* d = (TcDriverData*) handle; if (d->open) { FromEmulator from; from.type = EMULATOR_REQUEST_BDB_CLOSE_ASYNC; from.d = d; /* is this allowed here (?) */ driver_async (d->port, &d->magic, async_invoke, from_emulator_dup (&from), async_free); } data_unref (d); }
static int prepared_step(sqlite3_drv_t *drv, char *buffer, int buffer_size) { unsigned int prepared_index; long long_prepared_index; int index = 0; sqlite3_stmt *statement; async_sqlite3_command *async_command; ei_decode_version(buffer, &index, NULL); ei_decode_long(buffer, &index, &long_prepared_index); prepared_index = (unsigned int) long_prepared_index; if (prepared_index >= drv->prepared_count) { #ifdef DEBUG fprintf(drv->log, "Tried to make a step in prepared statement #%d, but maximum possible is #%d\n", prepared_index, drv->prepared_count - 1); fflush(drv->log); #endif return output_error(drv, SQLITE_MISUSE, "Trying to evaluate non-existent prepared statement"); } #ifdef DEBUG fprintf(drv->log, "Making a step in prepared statement #%d\n", prepared_index); fflush(drv->log); #endif statement = drv->prepared_stmts[prepared_index]; async_command = make_async_command_statement(drv, statement); if (sqlite3_threadsafe()) { drv->async_handle = driver_async(drv->port, &drv->key, sql_step_async, async_command, sql_free_async); } else { sql_step_async(async_command); ready_async((ErlDrvData) drv, (ErlDrvThreadData) async_command); } return 0; }
/* This function is called whenever the port is written to. The port should be in binary mode, see open_port/2. The ErlIOVec contains both a SysIOVec, suitable for writev, and one or more binaries. If these binaries should be retained, when the driver returns from outputv, they can be queued (using driver_enq_bin for instance), or if they are kept in a static or global variable, the reference counter can be incremented. THIS IMPLEMENTATION of the callback unpacks a set of headers from the input binary and constructs a Command object which is then submitted to the XslEngine. When the emulator is running in SMP mode, the actual processing is done on an async thread (using the driver_async submission mechanism) and the apply_transform function is used to wrap the XslEngine callback functions. The results of processing are handled on a main emulator thread in the ready_async driver callback. */ static void outputv(ErlDrvData drv_data, ErlIOVec *ev) { // char *error_msg; char *xml; char *xsl; char *data; DriverHandle *d = (DriverHandle*)drv_data; ErlDrvPort port = (ErlDrvPort)d->port; InputSpec *hspec; PayloadSize *hsize; XslTask *job; DriverContext *ctx; AsyncState *asd; DriverState state; ErlDrvTermData callee_pid = driver_caller(port); UInt8 *type1; UInt64 *size; if ((hspec = ALLOC(sizeof(InputSpec))) == NULL) { FAIL(port, "system_limit"); return; } if ((hsize = (PayloadSize*)try_driver_alloc(port, sizeof(PayloadSize), hspec)) == NULL) return; DBG("sizeof(uint64_t): %lu \n", sizeof(UInt64)); DBG("ev->vsize: %i \n", ev->vsize); // the first 8bit chunk holds the number of parameters type1 = ((UInt8*)ev->binv[1]->orig_bytes); hspec->param_grp_arity = *type1; // next two 8bit chunks hold the type specs type1++; hspec->input_kind = *type1; type1++; hspec->xsl_kind = *type1; // next two 64bit chunks hold the type specs type1++; size = ((UInt64*)type1); hsize->input_size = *size; size++; hsize->xsl_size = *size; // next comes the xml and xslt binaries, which may be in one of three places: // 1. if the XML binary is heap allocated, it'll be in the binv entry // 2. if the XML binary is not heap allocated, it'll be in the next binv entry // 3. if the XSL binary is not heap allocated, it'll be in the next binv entry // otherwise it'll bin in the (following) SysIOVec // if there is enough space remaining in a binv entry for the input document, // we pull it from there. Otherwise, it'll be collapsed into the first binary. size_t pos = ((sizeof(UInt8) * NUM_TYPE_HEADERS) + (sizeof(UInt64) * NUM_SIZE_HEADERS)); // INFO("pos = %lu \n", pos); UInt8 bin_idx = FIRST_BINV_ENTRY; // first entry is reserved if ((pos + hsize->input_size) <= ev->binv[bin_idx]->orig_size) { data = (char*)(&ev->binv[bin_idx]->orig_bytes[pos]); } else { data = ev->binv[++bin_idx]->orig_bytes; } // FIXME: find a way around NULL terminated strings and we can share the binary! xml = ALLOC(hsize->input_size + 1); xml[hsize->input_size] = '\0'; strncpy(xml, data, hsize->input_size); if (hsize->xsl_size < 64) { data = &ev->iov[++bin_idx].iov_base[0]; } else { data = ev->binv[++bin_idx]->orig_bytes; } xsl = ALLOC(hsize->xsl_size + 1); xsl[hsize->xsl_size] = '\0'; strncpy(xsl, data, hsize->xsl_size); if ((job = (XslTask*)try_driver_alloc(port, sizeof(XslTask), xml, xsl, hsize, hspec)) == NULL) return; if ((ctx = (DriverContext*)try_driver_alloc(port, sizeof(DriverContext), xml, xsl, hsize, hspec, job)) == NULL) return; if ((asd = (AsyncState*)try_driver_alloc(port, sizeof(AsyncState), xml, xsl, hsize, hspec, job, ctx)) == NULL) return; ctx->port = port; ctx->caller_pid = callee_pid; asd->driver = d; if ((asd->command = init_command(transform_command, ctx, job, NULL)) == NULL) { free_async_state(asd); FAIL(port, "system_limit"); return; } fprintf(stderr, "xml[spec: %lu, len:%lu]\n", (long unsigned int)hsize->input_size, strlen(xml)); fprintf(stderr, "xsl[spec: %lu, len:%lu]\n", (long unsigned int)hsize->xsl_size, strlen(xsl)); state = init_task(job, hsize, hspec, xml, xsl); switch (state) { case OutOfMemoryError: free_async_state(asd); FAIL(port, "system_limit"); return; case Success: /* driver_async will call engine->transform passing command, then call ready_async followed by cleanup_task. The synchronous code works something like this: (*a->async_invoke)(a->async_data); if (async_ready(prt, a->async_data)) { if (a->async_free != NULL) (*a->async_free)(a->async_data); } */ INFO("provider handoff: transform\n"); driver_async(port, NULL, apply_transform, asd, NULL); //cleanup_task); break; default: // TODO: it would be better if we didn't do "everthing else is an error" here // TODO: error!? break; } };
static void s1_outputv(ErlDrvData drv_data, ErlIOVec *ev) { descriptor_t *desc = (descriptor_t *) drv_data; unsigned char cmd; int p = 0, q = 1; callstate_t *c = NULL; int do_async_call = default_async_calls; unsigned long binlen; int index; void *tmp = NULL; binlen = binlen; index = index; tmp = tmp; if (desc == NULL || ev == NULL || ev->size < 1) { edtk_debug("%s: bad arg(s)", __FUNCTION__); return; } if (! EV_GET_CHAR(ev, &cmd, &p, &q)) { edtk_debug("%s: empty command", __FUNCTION__); reply_error(desc, EINVAL); } if ((c = sys_alloc(sizeof(callstate_t))) == NULL) { reply_error(desc, ENOMEM); return; } c->cmd = cmd; c->key = NULL; c->free = sys_free; c->xid = 0; /* XXX unused right now */ c->o.__expect = 1; /* Default is that expectation is always met */ edtk_debug("%s: my threadid = %lx, cmd = %d", __FUNCTION__, pthread_self(), cmd); switch (cmd) { case S1_DEBUG: EV_GET_UINT32(ev, &edtk_debug_flag, &p, &q); reply_ok_num(desc, edtk_debug_flag); /* Immediate reply */ sys_free(c); c = NULL; break; case S1_NULL: c->invoke = invoke_s1_null; break; case S1_OPEN: c->invoke = invoke_s1_open; EV_GET_UINT32(ev, &binlen, &p, &q); c->i.filename = (char *) EV_GETPOS(ev, p, q); if (edtk_ev_forward_N(ev, binlen, &p, &q, 1) < 0) { goto error; } EV_GET_UINT32(ev, &c->i.flags, &p, &q); break; case S1_GETFD: c->invoke = invoke_s1_getfd; EV_GET_UINT32(ev, &index, &p, &q); if (desc->valmap_fd[index] == -1) { goto error; } else { edtk_debug("%s: valmap fd index %d = 0x%lx", __FUNCTION__, index, desc->valmap_fd[index]); c->i.fd = desc->valmap_fd[index]; c->i.__valmap_fd_index = index; } break; case S1_SENDFD: c->invoke = invoke_s1_sendfd; EV_GET_UINT32(ev, &c->i.unixdom_fd, &p, &q); EV_GET_UINT32(ev, &c->i.fd_to_be_sent, &p, &q); break; case S1_RECEIVEFD: c->invoke = invoke_s1_receivefd; EV_GET_UINT32(ev, &c->i.unixdom_fd, &p, &q); break; case S1_CLOSE: c->invoke = invoke_s1_close; EV_GET_UINT32(ev, &index, &p, &q); if (index == -1 && 0 == 1) { edtk_debug("%s: valmap fd index %d = default value 0x%lx", __FUNCTION__, index, -1); c->i.fd = -1; c->i.__valmap_fd_index = -1; } else if (desc->valmap_fd[index] == -1) { goto error; } else { edtk_debug("%s: valmap fd index %d = 0x%lx", __FUNCTION__, index, desc->valmap_fd[index]); c->i.fd = desc->valmap_fd[index]; c->i.__valmap_fd_index = index; } break; } if (c != NULL) { if (do_async_call) { driver_async(desc->port, c->key, c->invoke, c, c->free); } else { /* ** Execute the bottom half right away, then send the result. */ (*(c->invoke))((void *) c); s1_ready_async((ErlDrvData) desc, (ErlDrvThreadData) c); /* ** c is already freed for us by s1_ready_async() */ } } return; error: if (c != NULL) { sys_free(c); } reply_error_atom(desc, am_badarg); }