Exemple #1
0
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;
  }
}
Exemple #2
0
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;
  }
}
Exemple #3
0
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);
      }
    }
  }
}
Exemple #4
0
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;
    }
}
Exemple #5
0
// 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;
};
Exemple #7
0
//-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~
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));
}
Exemple #8
0
// 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;
}
Exemple #9
0
// 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;
}
Exemple #10
0
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]);
    }
}