int start_native_gui(wxe_data *sd) { int res; wxe_status_m = erl_drv_mutex_create((char *) "wxe_status_m"); wxe_status_c = erl_drv_cond_create((char *)"wxe_status_c"); wxe_batch_locker_m = erl_drv_mutex_create((char *)"wxe_batch_locker_m"); wxe_batch_locker_c = erl_drv_cond_create((char *)"wxe_batch_locker_c"); init_caller = driver_connected(sd->port_handle); #ifdef __DARWIN__ res = erl_drv_steal_main_thread((char *)"wxwidgets", &wxe_thread,wxe_main_loop,(void *) sd->pdl,NULL); #else ErlDrvThreadOpts *opts = erl_drv_thread_opts_create((char *)"wx thread"); opts->suggested_stack_size = 8192; res = erl_drv_thread_create((char *)"wxwidgets", &wxe_thread,wxe_main_loop,(void *) sd->pdl,opts); erl_drv_thread_opts_destroy(opts); #endif if(res == 0) { erl_drv_mutex_lock(wxe_status_m); for(;wxe_status == WXE_NOT_INITIATED;) { erl_drv_cond_wait(wxe_status_c, wxe_status_m); } erl_drv_mutex_unlock(wxe_status_m); return wxe_status; } else { wxString msg; msg.Printf(wxT("Erlang failed to create wxe-thread %d\r\n"), res); send_msg("error", &msg); return -1; } }
int start_native_gui(wxe_data *sd) { int res; wxe_status_m = erl_drv_mutex_create((char *) "wxe_status_m"); wxe_status_c = erl_drv_cond_create((char *)"wxe_status_c"); wxe_batch_locker_m = erl_drv_mutex_create((char *)"wxe_batch_locker_m"); wxe_batch_locker_c = erl_drv_cond_create((char *)"wxe_batch_locker_c"); init_caller = driver_connected(sd->port); if((res = erl_drv_thread_create((char *)"wxwidgets", &wxe_thread,wxe_main_loop,(void *) sd->pdl,NULL)) == 0) { erl_drv_mutex_lock(wxe_status_m); for(;wxe_status == WXE_NOT_INITIATED;) { erl_drv_cond_wait(wxe_status_c, wxe_status_m); } erl_drv_mutex_unlock(wxe_status_m); return wxe_status; } else { wxString msg; msg.Printf(wxT("Erlang failed to create wxe-thread %d\r\n"), res); send_msg("error", &msg); return -1; } }
void WxeApp::dispatch_cb(wxList * batch, wxList * temp, ErlDrvTermData process) { int callback_returned = 0; while(true) { if (batch->size() > 0) { for( wxList::compatibility_iterator node = batch->GetFirst(); node; node = batch->GetFirst()) { wxeCommand *event = (wxeCommand *)node->GetData(); batch->Erase(node); if(event->caller == process || // Callbacks from CB process only event->op == WXE_CB_START || // Recursive event callback allow // Allow connect_cb during CB i.e. msg from wxe_server. event->caller == driver_connected(event->port)) { switch(event->op) { case WXE_BATCH_END: case WXE_BATCH_BEGIN: break; case WXE_CB_RETURN: memcpy(cb_buff, event->buffer, event->len); callback_returned = 1; return; case WXE_CB_START: // CB start from now accept message from CB process only process = event->caller; break; default: erl_drv_mutex_unlock(wxe_batch_locker_m); if(event->op < OPENGL_START) { // fprintf(stderr, " cb %d \r\n", event->op); wxe_dispatch(*event); } else { gl_dispatch(event->op,event->buffer,event->caller,event->bin); } erl_drv_mutex_lock(wxe_batch_locker_m); break; if(callback_returned) return; } delete event; } else { // fprintf(stderr, " sav %d \r\n", event->op); temp->Append(event); } } } else { if(callback_returned) { return; } // sleep until something happens //fprintf(stderr, "%s:%d sleep %d %d %d %d \r\n", __FILE__, __LINE__, batch->size(), callback_returned, blevel, is_callback);fflush(stderr); while(batch->size() == 0) { erl_drv_cond_wait(wxe_batch_locker_c, wxe_batch_locker_m); } } } }
static ErlDrvData innostore_drv_start(ErlDrvPort port, char* buffer) { PortState* state = (PortState*)driver_alloc(sizeof(PortState)); int worker_rc; memset(state, '\0', sizeof(PortState)); // Save handle to the port state->port = port; // Save the owner PID state->port_owner = driver_connected(port); // Initialize in the READY state state->port_state = STATE_READY; // Make sure port is running in binary mode set_port_control_flags(port, PORT_CONTROL_FLAG_BINARY); // Allocate a mutex and condition variable for the worker state->worker_lock = erl_drv_mutex_create("innostore_worker_lock"); state->worker_cv = erl_drv_cond_create("innostore_worker_cv"); // Spin up the worker worker_rc = erl_drv_thread_create("innostore_worker", &(state->worker), &innostore_worker, state, 0); if (state->worker_lock != NULL && state->worker_cv != NULL && worker_rc == 0) { return (ErlDrvData)state; } else { log("Innostore: Could not create port [lock=%p, cv=%p]\n", state->worker_lock, state->worker_cv); if (state->worker_cv != NULL) erl_drv_cond_destroy(state->worker_cv); if (state->worker_lock != NULL) erl_drv_mutex_destroy(state->worker_lock); driver_free(state); errno = worker_rc; return (ErlDrvData) ERL_DRV_ERROR_ERRNO; } }
// Initialize thread structure int dthread_init(dthread_t* thr, ErlDrvPort port) { ErlDrvSysInfo sys_info; memset(thr, 0, sizeof(dthread_t)); dthread_signal_init(thr); driver_system_info(&sys_info, sizeof(ErlDrvSysInfo)); // smp_support is used for message passing from thread to // calling process. if SMP is supported the message will go // directly to sender, otherwise it must be sent to port thr->smp_support = sys_info.smp_support; thr->port = port; thr->dport = driver_mk_port(port); thr->owner = driver_connected(port); if (!(thr->iq_mtx = erl_drv_mutex_create("iq_mtx"))) return -1; #ifdef __WIN32__ // create a manual reset event if (!(thr->iq_signal[0] = (ErlDrvEvent) CreateEvent(NULL, TRUE, FALSE, NULL))) { dthread_finish(thr); return -1; } DEBUGF("dthread_init: handle=%d", DTHREAD_EVENT(thr->iq_signal[0])); #else { int pfd[2]; if (pipe(pfd) < 0) { dthread_finish(thr); return -1; } DEBUGF("dthread_init: pipe[0]=%d,pidp[1]=%d", pfd[0], pfd[1]); thr->iq_signal[0] = (ErlDrvEvent) ((long)pfd[0]); thr->iq_signal[1] = (ErlDrvEvent) ((long)pfd[1]); INFOF("pipe: %d,%d", pfd[0], pfd[1]); } #endif return 0; }
// Called by the emulator when the driver is starting. static ErlDrvData start_driver(ErlDrvPort port, char *buff) { EdbcOciPortData *pd = zalloc(port, sizeof(EdbcOciPortData)); if (pd == NULL) { // TODO: use ERL_DRV_ERROR_ERRNO and provide out-of-memory info return ERL_DRV_ERROR_GENERAL; } ErlDrvSysInfo sys_info; driver_system_info(&sys_info, sizeof(ErlDrvSysInfo)); pd->send_term_requires_lock = (sys_info->smp_support == 0); pd->port = (void*)port; pd->owner = driver_connected(port); pd->mutex = erl_drv_mutex_create("edbc_oci_port_instance_mutex"); // some fields can't be initialized until we've got our hands on // the relevant configuration data at runtime... pd->worker_pool = NULL; pd->log = NULL; return (ErlDrvData)pd; };
//-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~ static ErlDrvData zmqdrv_start(ErlDrvPort port, char* /*cmd*/) { zmqdrv_fprintf("zmq port driver started by pid %lu\r\n", driver_connected(port)); return reinterpret_cast<ErlDrvData>(new zmq_drv_t(port)); }
// thread main! int uart_unix_main(void* arg) { dthread_t* self = (dthread_t*) arg; dthread_t* other = (dthread_t*) self->arg; dmessage_t* mp = NULL; dthread_poll_event_t ev, *evp; size_t nev; dterm_t term; uart_ctx_t ctx; ErlDrvTermData mp_from; ErlDrvTermData mp_ref; dthread_t* mp_source; int tmo; int r; DEBUGF("uart_unix: thread started"); uart_init(&ctx, self, other); dterm_init(&term); again_tmo: tmo = next_timeout(&ctx); again: nev = 0; evp = NULL; if (ctx.fd >= 0) { ev.event = (ErlDrvEvent) ((long)ctx.fd); ev.events = 0; if ((ctx.option.active != UART_PASSIVE) || ctx.recv) { ev.events |= ERL_DRV_READ; if (ctx.option.ptypkt && (ctx.fd != ctx.tty_fd)) ev.events |= ERL_DRV_EXCEP; } if (ctx.oq.mesg) ev.events |= ERL_DRV_WRITE; if (ev.events) { evp = &ev; nev = 1; } DEBUGF("ctx.fd=%d, ev.events=%d", ctx.fd, ev.events); } DEBUGF("uart_unix_main: nev=%d, events=%x, timeout = %d", nev, ev.events, tmo); r = dthread_poll(self, evp, &nev, tmo); if (r < 0) { DEBUGF("uart_unix_main: dthread_poll failed=%d", r); goto again_tmo; } else { DEBUGF("uart_unix_main: nev=%d, r=%d", nev, r); if (evp && (nev == 1)) { if (evp->revents & ERL_DRV_WRITE) process_output(&ctx, self); if (evp->revents & (ERL_DRV_READ|ERL_DRV_EXCEP)) { while((process_input(&ctx, self, 0) == 1) && (ctx.option.active != UART_PASSIVE)) ; } } tmo = next_timeout(&ctx); DEBUGF("uart_unix_main: timeout = %d", tmo); if (ctx.recv) { if (tmo == 0) { uart_async_error_am(&ctx, ctx.dport, ctx.caller, am_timeout); clear_timeout(&ctx); ctx.remain = 0; } } if (r == 0) goto again; // r>0 (number of messages) DEBUGF("about to receive message r=%d", r); if ((mp = dthread_recv(self, NULL)) == NULL) { DEBUGF("uart_unix_main: message was NULL"); goto again; } mp_from = mp->from; mp_ref = mp->ref; mp_source = mp->source; switch (mp->cmd) { case DTHREAD_STOP: DEBUGF("uart_unix_main: STOP"); close_device(&ctx); uart_final(&ctx); dmessage_free(mp); DEBUGF("uart_unix_main: EXIT"); dthread_exit(0); break; case DTHREAD_OUTPUT: // async send! DEBUGF("uart_unix_main: OUTPUT"); if (ctx.fd < 0) { dmessage_free(mp); goto again; } if (enq_output(&ctx, self, mp, 0) < 0) { mp = NULL; goto error; } goto again; case UART_CMD_CONNECT: { ErlDrvTermData owner; if (mp->used != 0) goto badarg; owner = driver_connected(self->port); self->owner = owner; other->owner = owner; goto ok; } case UART_CMD_CLOSE: DEBUGF("uart_unix_main: CLOSE"); close_device(&ctx); goto ok; case UART_CMD_SEND: // sync send DEBUGF("uart_unix_main: SEND"); if (ctx.fd < 0) goto ebadf; if (enq_output(&ctx, self, mp, mp_from) < 0) { mp = NULL; goto error; } goto again; case UART_CMD_SENDCHAR: // sync send DEBUGF("uart_unix_main: SENDCHAR"); if (ctx.fd < 0) goto ebadf; if (enq_output(&ctx, self, mp, mp_from) < 0) { mp = NULL; goto error; } goto again; case UART_CMD_RECV: { // <<Time:32, Length:32>> Time=0xffffffff=inf uint32_t tm; int len; DEBUGF("uart_unix_main: RECV"); if (ctx.fd < 0) goto ebadf; if (ctx.recv) goto ealready; if (mp->used != 8) goto badarg; if (ctx.option.active != UART_PASSIVE) goto badarg; tm = get_uint32((uint8_t*) mp->buffer); len = (int) get_uint32((uint8_t*) (mp->buffer+4)); if ((len < 0) || (len > UART_MAX_PACKET_SIZE)) goto badarg; ctx.ref = mp_ref; ctx.caller = mp_from; set_timeout(&ctx, tm); ctx.recv = 1; DEBUGF("recv timeout %lu", tm); process_input(&ctx, self, len); dmessage_free(mp); goto again_tmo; } case UART_CMD_UNRECV: { // argument is data to push back uart_buf_push(&ctx.ib, mp->buffer, mp->used); DEBUGF("unrecived %d bytes", ctx.ib.ptr - ctx.ib.ptr_start); if (ctx.option.active != UART_PASSIVE) { while((process_input(&ctx, self, 0) == 1) && (ctx.option.active != UART_PASSIVE)) ; } goto ok; } case UART_CMD_SETOPTS: { uart_com_state_t state = ctx.state; uart_opt_t option = ctx.option; uint32_t sflags = ctx.sflags; // parse & update options in state,option and sflag if (uart_parse_opts(mp->buffer, mp->used, &state, &option, &sflags) < 0) goto badarg; // apply the changed values if ((r=apply_opts(&ctx, &state, &option, sflags)) < 0) goto error; if (r == 1) { while((process_input(&ctx, self, 0) == 1) && (ctx.option.active != UART_PASSIVE)) ; } goto ok; } case UART_CMD_GETOPTS: { dterm_mark_t m1; dterm_mark_t m2; // {Ref, {ok,List}} || {Ref, {error,Reason}} dterm_tuple_begin(&term, &m1); { dterm_uint(&term, mp_ref); dterm_tuple_begin(&term, &m2); { dterm_atom(&term, am_ok); if (uart_get_opts(&term, &ctx,(uint8_t*)mp->buffer,mp->used) < 0) { dterm_reset(&term); goto badarg; } } dterm_tuple_end(&term, &m2); } dterm_tuple_end(&term, &m1); dthread_port_send_dterm(mp_source, self, mp_from, &term); dterm_reset(&term); dmessage_free(mp); goto again; } case UART_CMD_GET_MODEM: { dterm_mark_t m1; dterm_mark_t m2; uart_modem_state_t mstate; if (ctx.tty_fd < 0) goto ebadf; if (get_modem_state(ctx.tty_fd, &mstate) < 0) goto error; dterm_tuple_begin(&term, &m1); { dterm_uint(&term, mp_ref); dterm_tuple_begin(&term, &m2); { dterm_atom(&term, am_ok); modem_state_dterm(&term, mstate); } dterm_tuple_end(&term, &m2); } dterm_tuple_end(&term, &m1); dthread_port_send_dterm(mp_source, self, mp_from, &term); dterm_reset(&term); dmessage_free(mp); goto again; } case UART_CMD_SET_MODEM: { uart_modem_state_t mstate; if (ctx.tty_fd < 0) goto ebadf; if (mp->used != 4) goto badarg; mstate = (uart_modem_state_t) get_uint32((uint8_t*) mp->buffer); if (set_modem_state(ctx.tty_fd, mstate, 1) < 0) goto error; goto ok; } case UART_CMD_CLR_MODEM: { uart_modem_state_t mstate; if (ctx.tty_fd < 0) goto ebadf; if (mp->used != 4) goto badarg; mstate = (uart_modem_state_t) get_uint32((uint8_t*) mp->buffer); if (set_modem_state(ctx.tty_fd, mstate, 0) < 0) goto error; goto ok; } case UART_CMD_HANGUP: { struct termios tio; int r; if (ctx.tty_fd < 0) goto ebadf; if (mp->used != 0) goto badarg; if ((r = tcgetattr(ctx.tty_fd, &tio)) < 0) { INFOF("tcgetattr: error=%s\n", strerror(errno)); goto badarg; } cfsetispeed(&tio, B0); cfsetospeed(&tio, B0); if ((r = tcsetattr(ctx.tty_fd, TCSANOW, &tio)) < 0) { INFOF("tcsetattr: error=%s\n", strerror(errno)); goto badarg; } goto ok; } case UART_CMD_BREAK: { int duration; if (ctx.tty_fd < 0) goto ebadf; if (mp->used != 4) goto badarg; duration = (int) get_uint32((uint8_t*) mp->buffer); if (tcsendbreak(ctx.tty_fd, duration) < 0) goto error; goto ok; } case UART_CMD_FLOW: if (ctx.tty_fd < 0) goto ebadf; if (mp->used != 1) goto badarg; switch(mp->buffer[0]) { case 0: r = tcflow(ctx.tty_fd, TCIOFF); break; case 1: r = tcflow(ctx.tty_fd, TCION); break; case 2: r = tcflow(ctx.tty_fd, TCOOFF); break; case 3: r = tcflow(ctx.tty_fd, TCOON); break; default: goto badarg; break; } if (r < 0) goto error; goto ok; default: goto badarg; } } ok: dthread_port_send_ok(mp_source, self, mp_from, mp_ref); if (mp) dmessage_free(mp); goto again; ebadf: errno = EBADF; goto error; badarg: errno = EINVAL; goto error; ealready: errno = EALREADY; goto error; error: dthread_port_send_error(mp_source, self, mp_from, mp_ref, uart_errno(&ctx)); if (mp) dmessage_free(mp); goto again; }
// thread main! int uart_win32_main(void* arg) { dthread_t* self = (dthread_t*) arg; dthread_t* other = (dthread_t*) self->arg; dmessage_t* mp = NULL; dthread_poll_event_t ev[3]; dthread_poll_event_t* evp; size_t nev; dterm_t term; uart_ctx_t ctx; ErlDrvTermData mp_from; ErlDrvTermData mp_ref; dthread_t* mp_source; int tmo; int r; DEBUGF("uart_win32: thread started"); uart_init(&ctx, self, other); dterm_init(&term); again_tmo: tmo = next_timeout(&ctx); again: nev = 0; if (ctx.writing) { ev[nev].event = (ErlDrvEvent) ctx.out.hEvent; ev[nev].events = ERL_DRV_READ; // yepp, even for write nev++; } while(!ctx.reading && (ctx.recv || (ctx.option.active != UART_PASSIVE))) process_input(&ctx, self, 0); if (ctx.reading) { ev[nev].event = (ErlDrvEvent) ctx.in.hEvent; ev[nev].events = ERL_DRV_READ; nev++; } evp = nev ? &ev[0] : NULL; DEBUGF("uart_win32_main: ctx.fh=%d, nev=%u, timeout = %d", ctx.fh, nev, tmo); r = dthread_poll(self, evp, &nev, tmo); if (r < 0) { DEBUGF("uart_win32_main: dthread_poll failed=%d", r); goto again_tmo; } else { DWORD i; DEBUGF("uart_win32_main: nev=%u, r=%d", nev, r); for (i = 0; i < nev; i++) { if (ev[i].revents & ERL_DRV_READ) { if (ev[i].event == (ErlDrvEvent) ctx.in.hEvent) { while((process_input(&ctx, self, 0) == 1) && (ctx.option.active != UART_PASSIVE)) ; } else if (ev[i].event == (ErlDrvEvent) ctx.out.hEvent) { process_output(&ctx, self); } } } tmo = next_timeout(&ctx); DEBUGF("uart_win32_main: timeout = %d", tmo); if (ctx.recv) { if (tmo == 0) { uart_async_error_am(&ctx, ctx.dport, ctx.caller, am_timeout); clear_timeout(&ctx); ctx.remain = 0; } } if (r == 0) goto again; // r>0 (number of messages) DEBUGF("about to receive message r=%d", r); if ((mp = dthread_recv(self, NULL)) == NULL) { DEBUGF("uart_win32_main: message was NULL"); goto again; } mp_from = mp->from; mp_ref = mp->ref; mp_source = mp->source; switch (mp->cmd) { case DTHREAD_STOP: DEBUGF("uart_win32_main: STOP"); close_device(&ctx); uart_final(&ctx); dmessage_free(mp); DEBUGF("uart_win32_main: EXIT"); dthread_exit(0); break; case DTHREAD_OUTPUT: // async send! DEBUGF("uart_win32_main: OUTPUT"); if (ctx.fh == INVALID_HANDLE_VALUE) { dmessage_free(mp); goto again; } if (enq_output(&ctx, self, mp, 0) < 0) { mp = NULL; goto error; } goto again; case UART_CMD_CONNECT: { ErlDrvTermData owner; if (mp->used != 0) goto badarg; owner = driver_connected(self->port); self->owner = owner; other->owner = owner; goto ok; } case UART_CMD_CLOSE: DEBUGF("uart_win32_main: CLOSE"); close_device(&ctx); goto ok; case UART_CMD_SEND: // sync send DEBUGF("uart_win32_main: SEND"); if (ctx.fh == INVALID_HANDLE_VALUE) goto ebadf; if (enq_output(&ctx, self, mp, mp_from) < 0) { mp = NULL; goto error; } goto again; case UART_CMD_SENDCHAR: // sync send DEBUGF("uart_win32_main: SENDCHAR"); if (ctx.fh == INVALID_HANDLE_VALUE) goto ebadf; if (enq_output(&ctx, self, mp, mp_from) < 0) { mp = NULL; goto error; } goto again; case UART_CMD_RECV: { // <<Time:32, Length:32>> Time=0xffffffff=inf uint32_t tm; int len; DEBUGF("uart_win32_main: RECV"); if (ctx.fh == INVALID_HANDLE_VALUE) goto ebadf; if (ctx.recv) goto ealready; if (mp->used != 8) goto badarg; if (ctx.option.active != UART_PASSIVE) goto badarg; tm = get_uint32((uint8_t*) mp->buffer); len = (int) get_uint32((uint8_t*) (mp->buffer+4)); if ((len < 0) || (len > UART_MAX_PACKET_SIZE)) goto badarg; ctx.ref = mp_ref; ctx.caller = mp_from; set_timeout(&ctx, tm); ctx.recv = 1; DEBUGF("recv timeout %lu", tm); process_input(&ctx, self, len); dmessage_free(mp); goto again_tmo; } case UART_CMD_UNRECV: { // argument is data to push back uart_buf_push(&ctx.ib, mp->buffer, mp->used); DEBUGF("unrecived %d bytes", ctx.ib.ptr - ctx.ib.ptr_start); if (ctx.option.active != UART_PASSIVE) { while((process_input(&ctx, self, 0) == 1) && (ctx.option.active != UART_PASSIVE)) ; } goto ok; } case UART_CMD_SETOPTS: { uart_com_state_t state = ctx.state; uart_opt_t option = ctx.option; uint32_t sflags = ctx.sflags; // parse & update options in state,option and sflag if (uart_parse_opts(mp->buffer, mp->used, &state, &option, &sflags) < 0) goto badarg; // apply the changed values if ((r=apply_opts(&ctx, &state, &option, sflags)) < 0) { goto error; } goto ok; } case UART_CMD_GETOPTS: { dterm_mark_t m1; dterm_mark_t m2; // {Ref, {ok,List}} || {Ref, {error,Reason}} dterm_tuple_begin(&term, &m1); { dterm_uint(&term, mp_ref); dterm_tuple_begin(&term, &m2); { dterm_atom(&term, am_ok); if (uart_get_opts(&term, &ctx,(uint8_t*)mp->buffer,mp->used) < 0) { dterm_reset(&term); goto badarg; } } dterm_tuple_end(&term, &m2); } dterm_tuple_end(&term, &m1); dthread_port_send_dterm(mp_source, self, mp_from, &term); dterm_reset(&term); dmessage_free(mp); goto again; } case UART_CMD_GET_MODEM: { dterm_mark_t m1; dterm_mark_t m2; uart_modem_state_t mstate; if (ctx.fh == INVALID_HANDLE_VALUE) goto ebadf; if (get_modem_state(ctx.fh, &mstate) < 0) goto error; dterm_tuple_begin(&term, &m1); { dterm_uint(&term, mp_ref); dterm_tuple_begin(&term, &m2); { dterm_atom(&term, am_ok); modem_state_dterm(&term, mstate); } dterm_tuple_end(&term, &m2); } dterm_tuple_end(&term, &m1); dthread_port_send_dterm(mp_source, self, mp_from, &term); dterm_reset(&term); dmessage_free(mp); goto again; } case UART_CMD_SET_MODEM: { uart_modem_state_t mstate; if (ctx.fh == INVALID_HANDLE_VALUE) goto ebadf; if (mp->used != 4) goto badarg; mstate = (uart_modem_state_t) get_uint32((uint8_t*) mp->buffer); if (set_modem_state(ctx.fh, mstate, 1) < 0) goto error; goto ok; } case UART_CMD_CLR_MODEM: { uart_modem_state_t mstate; if (ctx.fh == INVALID_HANDLE_VALUE) goto ebadf; if (mp->used != 4) goto badarg; mstate = (uart_modem_state_t) get_uint32((uint8_t*) mp->buffer); if (set_modem_state(ctx.fh, mstate, 0) < 0) goto error; goto ok; } case UART_CMD_HANGUP: { if (ctx.fh == INVALID_HANDLE_VALUE) goto ebadf; if (mp->used != 0) goto badarg; // FIXME? goto ok; } case UART_CMD_BREAK: { int duration; if (ctx.fh == INVALID_HANDLE_VALUE) goto ebadf; if (mp->used != 4) goto badarg; duration = (int) get_uint32((uint8_t*) mp->buffer); if (!EscapeCommFunction(ctx.fh, SETBREAK)) { DEBUG_ERROR("EscapeCommFunction: error %d", GetLastError()); goto error; } Sleep(duration); if (!EscapeCommFunction(ctx.fh, CLRBREAK)) { DEBUG_ERROR("EscapeCommFunction: error %d", GetLastError()); goto error; } goto ok; } case UART_CMD_FLOW: if (ctx.fh == INVALID_HANDLE_VALUE) goto ebadf; if (mp->used != 1) goto badarg; switch(mp->buffer[0]) { case 0: if (!EscapeCommFunction(ctx.fh, SETXOFF)) { DEBUG_ERROR("EscapeCommFunction: error %d", GetLastError()); goto error; } break; case 1: if (!EscapeCommFunction(ctx.fh, SETXON)) { DEBUG_ERROR("EscapeCommFunction: error %d", GetLastError()); goto error; } break; case 2: // TransmitCommChar(ctx.fh, XOFF); break; case 3: // TransmitCommChar(ctx.fh, XON); break; default: goto badarg; } goto ok; default: goto badarg; } } ok: dthread_port_send_ok(mp_source, self, mp_from, mp_ref); if (mp) dmessage_free(mp); goto again; ebadf: errno = EBADF; goto error; badarg: errno = EINVAL; goto error; ealready: errno = EBUSY; goto error; error: dthread_port_send_error(mp_source, self, mp_from, mp_ref, uart_errno(&ctx)); if (mp) dmessage_free(mp); goto again; }
static void send_term_drv_run(ErlDrvData port, char *buf, ErlDrvSizeT count) { char buf7[1024]; ErlDrvTermData spec[1024]; ErlDrvTermData* msg = spec; ErlDrvBinary* bins[15]; int bin_ix = 0; ErlDrvSInt64 s64[15]; int s64_ix = 0; ErlDrvUInt64 u64[15]; int u64_ix = 0; int i = 0; for (i=0; i<count; i++) switch (buf[i]) { case 0: msg[0] = ERL_DRV_NIL; msg += 1; break; case 1: /* Most term types inside a tuple. */ { double f = 3.1416; msg[0] = ERL_DRV_ATOM; msg[1] = driver_mk_atom("blurf"); msg[2] = ERL_DRV_INT; msg[3] = (ErlDrvTermData) 42; msg[4] = ERL_DRV_NIL; msg[5] = ERL_DRV_INT; msg[6] = (ErlDrvTermData) -42; msg[7] = ERL_DRV_TUPLE; msg[8] = (ErlDrvTermData) 0; msg[9] = ERL_DRV_PORT; msg[10] = driver_mk_port(erlang_port); msg[11] = ERL_DRV_STRING_CONS; msg[12] = (ErlDrvTermData) "abc"; msg[13] = (ErlDrvTermData) 3; msg[14] = ERL_DRV_LIST; msg[15] = (ErlDrvTermData) 3; msg[16] = ERL_DRV_STRING; msg[17] = (ErlDrvTermData) "kalle"; msg[18] = (ErlDrvTermData) 5; msg[19] = ERL_DRV_FLOAT; msg[20] = (ErlDrvTermData) &f; msg[21] = ERL_DRV_PID; msg[22] = driver_connected(erlang_port); msg[23] = ERL_DRV_MAP; msg[24] = (ErlDrvTermData) 0; msg[25] = ERL_DRV_TUPLE; msg[26] = (ErlDrvTermData) 8; msg += 27; } break; case 2: /* Deep stack */ { int i; for (i = 0; i < 400; i += 2) { msg[i] = ERL_DRV_INT; msg[i+1] = (ErlDrvTermData) (i / 2); } msg[i] = ERL_DRV_NIL; msg[i+1] = ERL_DRV_LIST; msg[i+2] = (ErlDrvTermData) 201; msg += i+3; } break; case 3: /* Binaries */ { ErlDrvBinary* bin; int i; bin = bins[bin_ix++] = driver_alloc_binary(256); for (i = 0; i < 256; i++) { bin->orig_bytes[i] = i; } msg[0] = ERL_DRV_BINARY; msg[1] = (ErlDrvTermData) bin; msg[2] = (ErlDrvTermData) 256; msg[3] = (ErlDrvTermData) 0; msg[4] = ERL_DRV_BINARY; msg[5] = (ErlDrvTermData) bin; msg[6] = (ErlDrvTermData) 256-23-17; msg[7] = (ErlDrvTermData) 23; msg[8] = ERL_DRV_TUPLE; msg[9] = (ErlDrvTermData) 2; msg += 10; } break; case 4: /* Pids */ msg[0] = ERL_DRV_PID; msg[1] = driver_connected(erlang_port); msg[2] = ERL_DRV_PID; msg[3] = driver_caller(erlang_port); msg[4] = ERL_DRV_TUPLE; msg[5] = (ErlDrvTermData) 2; msg += 6; break; case 5: msg += make_ext_term_list(msg, 0); break; case 6: msg[0] = ERL_DRV_INT; msg[1] = ~((ErlDrvTermData) 0); msg[2] = ERL_DRV_UINT; msg[3] = ~((ErlDrvTermData) 0); msg[4] = ERL_DRV_TUPLE; msg[5] = (ErlDrvTermData) 2; msg += 6; break; case 7: { int len = 0; memset(buf7, 17, sizeof(buf7)); /* empty heap binary */ msg[len++] = ERL_DRV_BUF2BINARY; msg[len++] = (ErlDrvTermData) NULL; /* NULL is ok if size == 0 */ msg[len++] = (ErlDrvTermData) 0; /* empty heap binary again */ msg[len++] = ERL_DRV_BUF2BINARY; msg[len++] = (ErlDrvTermData) buf7; /* ptr is ok if size == 0 */ msg[len++] = (ErlDrvTermData) 0; /* heap binary */ msg[len++] = ERL_DRV_BUF2BINARY; msg[len++] = (ErlDrvTermData) buf7; msg[len++] = (ErlDrvTermData) 17; /* off heap binary */ msg[len++] = ERL_DRV_BUF2BINARY; msg[len++] = (ErlDrvTermData) buf7; msg[len++] = (ErlDrvTermData) sizeof(buf7); msg[len++] = ERL_DRV_TUPLE; msg[len++] = (ErlDrvTermData) 4; msg += len; break; } case 8: msg[0] = ERL_DRV_NIL; msg += 1; break; case 9: msg[0] = ERL_DRV_ATOM; msg[1] = (ErlDrvTermData) driver_mk_atom(""); msg += 2; break; case 10: msg[0] = ERL_DRV_ATOM; msg[1] = (ErlDrvTermData) driver_mk_atom("an_atom"); msg += 2; break; case 11: msg[0] = ERL_DRV_INT; msg[1] = (ErlDrvTermData) -4711; msg += 2; break; case 12: msg[0] = ERL_DRV_UINT; msg[1] = (ErlDrvTermData) 4711; msg += 2; break; case 13: msg[0] = ERL_DRV_PORT; msg[1] = driver_mk_port(erlang_port); msg += 2; break; case 14: { ErlDrvBinary *dbin = bins[bin_ix++] = driver_alloc_binary(0); msg[0] = ERL_DRV_BINARY; msg[1] = (ErlDrvTermData) dbin; msg[2] = (ErlDrvTermData) 0; msg[3] = (ErlDrvTermData) 0; msg += 4; break; } case 15: { static const char buf[] = "hejsan"; ErlDrvBinary *dbin = bins[bin_ix++] = driver_alloc_binary(sizeof(buf)-1); if (dbin) memcpy((void *) dbin->orig_bytes, (void *) buf, sizeof(buf)-1); msg[0] = ERL_DRV_BINARY; msg[1] = (ErlDrvTermData) dbin; msg[2] = (ErlDrvTermData) (dbin ? sizeof(buf)-1 : 0); msg[3] = (ErlDrvTermData) 0; msg += 4; break; } case 16: msg[0] = ERL_DRV_BUF2BINARY; msg[1] = (ErlDrvTermData) NULL; msg[2] = (ErlDrvTermData) 0; msg += 3; break; case 17: { static const char buf[] = ""; msg[0] = ERL_DRV_BUF2BINARY; msg[1] = (ErlDrvTermData) buf; msg[2] = (ErlDrvTermData) sizeof(buf)-1; msg += 3; break; } case 18: { static const char buf[] = "hoppsan"; msg[0] = ERL_DRV_BUF2BINARY; msg[1] = (ErlDrvTermData) buf; msg[2] = (ErlDrvTermData) sizeof(buf)-1; msg += 3; break; } case 19: msg[0] = ERL_DRV_STRING; msg[1] = (ErlDrvTermData) buf; msg[2] = (ErlDrvTermData) 0; msg += 3; break; case 20: { static const char buf[] = ""; msg[0] = ERL_DRV_STRING; msg[1] = (ErlDrvTermData) buf; msg[2] = (ErlDrvTermData) sizeof(buf)-1; msg += 3; break; } case 21: { static const char buf[] = "hippsan"; msg[0] = ERL_DRV_STRING; msg[1] = (ErlDrvTermData) buf; msg[2] = (ErlDrvTermData) sizeof(buf)-1; msg += 3; break; } case 22: msg[0] = ERL_DRV_TUPLE; msg[1] = (ErlDrvTermData) 0; msg += 2; break; case 23: msg[0] = ERL_DRV_NIL; msg[1] = ERL_DRV_LIST; msg[2] = (ErlDrvTermData) 1; msg += 3; break; case 24: msg[0] = ERL_DRV_PID; msg[1] = driver_connected(erlang_port); msg += 2; break; case 25: msg[0] = ERL_DRV_NIL; msg[1] = ERL_DRV_STRING_CONS; msg[2] = (ErlDrvTermData) ""; msg[3] = (ErlDrvTermData) 0; msg += 4; break; case 26: { static double my_float = 0.0; msg[0] = ERL_DRV_FLOAT; msg[1] = (ErlDrvTermData) &my_float; msg += 2; break; } case 27: { static char buf[] = {131, 106}; /* [] */ msg[0] = ERL_DRV_EXT2TERM; msg[1] = (ErlDrvTermData) buf; msg[2] = (ErlDrvTermData) sizeof(buf); msg += 3; break; } case 28: { ErlDrvUInt64* x = &u64[u64_ix++]; *x = ~((ErlDrvUInt64) 0); msg[0] = ERL_DRV_UINT64; msg[1] = (ErlDrvTermData) x; msg += 2; break; } case 29: { ErlDrvUInt64* x = &u64[u64_ix++]; *x = ((ErlDrvUInt64) 4711) << 32; msg[0] = ERL_DRV_UINT64; msg[1] = (ErlDrvTermData) x; msg += 2; break; } case 30: { ErlDrvUInt64* x = &u64[u64_ix++]; *x = 4711; msg[0] = ERL_DRV_UINT64; msg[1] = (ErlDrvTermData) x; msg += 2; break; } case 31: { ErlDrvUInt64* x = &u64[u64_ix++]; *x = 0; msg[0] = ERL_DRV_UINT64; msg[1] = (ErlDrvTermData) x; msg += 2; break; } case 32: { ErlDrvSInt64* x = &s64[s64_ix++]; *x = ((((ErlDrvUInt64) 0x7fffffff) << 32) | ((ErlDrvUInt64) 0xffffffff)); msg[0] = ERL_DRV_INT64; msg[1] = (ErlDrvTermData) x; msg += 2; break; } case 33: { ErlDrvSInt64* x = &s64[s64_ix++]; *x = (ErlDrvSInt64) (((ErlDrvUInt64) 4711) << 32); msg[0] = ERL_DRV_INT64; msg[1] = (ErlDrvTermData) x; msg += 2; break; } case 34: { ErlDrvSInt64* x = &s64[s64_ix++]; *x = 4711; msg[0] = ERL_DRV_INT64; msg[1] = (ErlDrvTermData) x; msg += 2; break; } case 35: { ErlDrvSInt64* x = &s64[s64_ix++]; *x = 0; msg[0] = ERL_DRV_INT64; msg[1] = (ErlDrvTermData) x; msg += 2; break; } case 36: { ErlDrvSInt64* x = &s64[s64_ix++]; *x = -1; msg[0] = ERL_DRV_INT64; msg[1] = (ErlDrvTermData) x; msg += 2; break; } case 37: { ErlDrvSInt64* x = &s64[s64_ix++]; *x = -4711; msg[0] = ERL_DRV_INT64; msg[1] = (ErlDrvTermData) x; msg += 2; break; } case 38: { ErlDrvSInt64* x = &s64[s64_ix++]; *x = ((ErlDrvSInt64) ((ErlDrvUInt64) 4711) << 32)*-1; msg[0] = ERL_DRV_INT64; msg[1] = (ErlDrvTermData) x; msg += 2; break; } case 39: { ErlDrvSInt64* x = &s64[s64_ix++]; *x = ((ErlDrvSInt64) 1) << 63; msg[0] = ERL_DRV_INT64; msg[1] = (ErlDrvTermData) x; msg += 2; break; } case 40: { msg[0] = ERL_DRV_MAP; msg[1] = (ErlDrvTermData) 0; msg += 2; break; } case 41: /* Most term types inside a map */ case 42: { double f = 3.1416; if (buf[i] == 41) { *msg++ = ERL_DRV_ATOM; *msg++ = driver_mk_atom("blurf"); } *msg++ = ERL_DRV_INT; *msg++ = (ErlDrvTermData)42; *msg++ = ERL_DRV_NIL; *msg++ = ERL_DRV_INT; *msg++ = (ErlDrvTermData)-42; *msg++ = ERL_DRV_TUPLE; *msg++ = (ErlDrvTermData)0; *msg++ = ERL_DRV_PORT; *msg++ = driver_mk_port(erlang_port); *msg++ = ERL_DRV_STRING_CONS; *msg++ = (ErlDrvTermData)"abc"; *msg++ = (ErlDrvTermData)3; *msg++ = ERL_DRV_LIST; *msg++ = (ErlDrvTermData)3; *msg++ = ERL_DRV_STRING; *msg++ = (ErlDrvTermData)"kalle"; *msg++ = (ErlDrvTermData)5; *msg++ = ERL_DRV_FLOAT; *msg++ = (ErlDrvTermData)&f; *msg++ = ERL_DRV_PID; *msg++ = driver_connected(erlang_port); *msg++ = ERL_DRV_MAP; *msg++ = (ErlDrvTermData)0; if (buf[i] == 42) { *msg++ = ERL_DRV_ATOM; *msg++ = driver_mk_atom("blurf"); } *msg++ = ERL_DRV_MAP; *msg++ = (ErlDrvTermData)4; break; } case 127: /* Error cases */ { long refc; ErlDrvBinary* bin = bins[bin_ix++] = driver_alloc_binary(256); FAIL_TERM(msg, 0); msg[0] = ERL_DRV_LIST; msg[1] = (ErlDrvTermData) 0; FAIL_TERM(msg, 2); /* Not an atom */ msg[0] = ERL_DRV_ATOM; msg[1] = (ErlDrvTermData) driver_connected(erlang_port); FAIL_TERM(msg, 2); msg[0] = ERL_DRV_ATOM; msg[1] = driver_term_nil; FAIL_TERM(msg, 2); /* Not a pid */ msg[0] = ERL_DRV_PID; msg[1] = (ErlDrvTermData) driver_mk_atom("blurf"); FAIL_TERM(msg, 2); msg[0] = ERL_DRV_PID; msg[1] = driver_term_nil; FAIL_TERM(msg, 2); /* Not a port */ msg[0] = ERL_DRV_PORT; msg[1] = (ErlDrvTermData) driver_mk_atom("blurf"); FAIL_TERM(msg, 2); msg[0] = ERL_DRV_PORT; msg[1] = driver_term_nil; FAIL_TERM(msg, 2); /* Missing parameter on stack */ msg[0] = ERL_DRV_STRING_CONS; msg[1] = (ErlDrvTermData) "abc"; msg[2] = (ErlDrvTermData) 3; FAIL_TERM(msg, 3); /* * The first binary reference is correct, the second is incorrect. * There should not be any "binary leak". */ msg[0] = ERL_DRV_BINARY; msg[1] = (ErlDrvTermData) bin; msg[2] = (ErlDrvTermData) 256; msg[3] = (ErlDrvTermData) 0; msg[4] = ERL_DRV_BINARY; msg[5] = (ErlDrvTermData) bin; msg[6] = (ErlDrvTermData) 257; msg[7] = (ErlDrvTermData) 0; msg[8] = ERL_DRV_TUPLE; msg[9] = (ErlDrvTermData) 2; FAIL_TERM(msg, 10); msg[0] = ERL_DRV_BINARY; msg[1] = (ErlDrvTermData) bin; msg[2] = (ErlDrvTermData) 256; msg[3] = (ErlDrvTermData) 0; msg[4] = ERL_DRV_BINARY; msg[5] = (ErlDrvTermData) bin; msg[6] = (ErlDrvTermData) 256; msg[7] = (ErlDrvTermData) 50; msg[8] = ERL_DRV_TUPLE; msg[9] = (ErlDrvTermData) 2; FAIL_TERM(msg, 10); /* * We have succefully built two binaries. We expect the ref count * to be 1 (SMP) or 3 (non-SMP). */ refc = driver_binary_get_refc(bin); if (refc > 3) { char sbuf[128]; sprintf(sbuf, "bad_refc:%ld", refc); driver_failure_atom(erlang_port, sbuf); } driver_free_binary(bin); FAIL_TERM(msg, make_ext_term_list(msg, 1)); /* * Check that we fail for missing args. * * We setup valid terms but pass a too small size. We * want valid terms since we want to verify that the * failure really is due to the small size. */ msg[0] = ERL_DRV_ATOM; msg[1] = (ErlDrvTermData) driver_mk_atom("an_atom"); FAIL_TERM(msg, 1); msg[0] = ERL_DRV_INT; msg[1] = (ErlDrvTermData) -4711; FAIL_TERM(msg, 1); msg[0] = ERL_DRV_UINT; msg[1] = (ErlDrvTermData) 4711; FAIL_TERM(msg, 1); msg[0] = ERL_DRV_PORT; msg[1] = driver_mk_port(erlang_port); FAIL_TERM(msg, 1); { char buf[] = "hejsan"; ErlDrvBinary *dbin = driver_alloc_binary(sizeof(buf)-1); if (!dbin) driver_failure_posix(erlang_port, ENOMEM); else { memcpy((void *) dbin->orig_bytes, (void *) buf, sizeof(buf)-1); msg[0] = ERL_DRV_BINARY; msg[1] = (ErlDrvTermData) dbin; msg[2] = (ErlDrvTermData) sizeof(buf)-1; msg[3] = (ErlDrvTermData) 0; FAIL_TERM(msg, 1); FAIL_TERM(msg, 2); FAIL_TERM(msg, 3); driver_free_binary(dbin); } } { char buf[] = "hoppsan"; msg[0] = ERL_DRV_BUF2BINARY; msg[1] = (ErlDrvTermData) buf; msg[2] = (ErlDrvTermData) sizeof(buf)-1; FAIL_TERM(msg, 1); FAIL_TERM(msg, 2); } { char buf[] = "hippsan"; msg[0] = ERL_DRV_STRING; msg[1] = (ErlDrvTermData) buf; msg[2] = (ErlDrvTermData) sizeof(buf)-1; FAIL_TERM(msg, 1); FAIL_TERM(msg, 2); } msg[0] = ERL_DRV_TUPLE; msg[1] = (ErlDrvTermData) 0; FAIL_TERM(msg, 1); msg[0] = ERL_DRV_NIL; msg[1] = ERL_DRV_LIST; msg[2] = (ErlDrvTermData) 1; FAIL_TERM(msg, 2); msg[0] = ERL_DRV_PID; msg[1] = driver_connected(erlang_port); FAIL_TERM(msg, 1); msg[0] = ERL_DRV_NIL; msg[1] = ERL_DRV_STRING_CONS; msg[2] = (ErlDrvTermData) ""; msg[3] = (ErlDrvTermData) 0; FAIL_TERM(msg, 2); FAIL_TERM(msg, 3); { double my_float = 0.0; msg[0] = ERL_DRV_FLOAT; msg[1] = (ErlDrvTermData) &my_float; FAIL_TERM(msg, 1); } { char buf[] = {131, 106}; /* [] */ msg[0] = ERL_DRV_EXT2TERM; msg[1] = (ErlDrvTermData) buf; msg[2] = (ErlDrvTermData) sizeof(buf); FAIL_TERM(msg, 1); FAIL_TERM(msg, 2); } msg[0] = ERL_DRV_MAP; msg[1] = (ErlDrvTermData) 0; FAIL_TERM(msg, 1); /* map with duplicate key */ msg[0] = ERL_DRV_ATOM; msg[1] = driver_mk_atom("key"); msg[2] = ERL_DRV_NIL; msg[3] = ERL_DRV_ATOM; msg[4] = driver_mk_atom("key"); msg[5] = ERL_DRV_INT; msg[6] = (ErlDrvTermData) -4711; msg[7] = ERL_DRV_MAP; msg[8] = 2; FAIL_TERM(msg, 9); /* Signal end of test case */ msg[0] = ERL_DRV_NIL; erl_drv_output_term(driver_mk_port(erlang_port), msg, 1); return; } break; default: driver_failure_atom(erlang_port, "bad_request"); break; } if (count > 1) { *msg++ = ERL_DRV_NIL; *msg++ = ERL_DRV_LIST; *msg++ = count + 1; } output_term(spec, msg-spec); if ((bin_ix|s64_ix|u64_ix) > 15) abort(); while (bin_ix) { driver_free_binary(bins[--bin_ix]); } }