예제 #1
0
파일: dthread.c 프로젝트: relabsoss/uart
int dthread_signal_set(dthread_t* thr)
{
#ifdef __WIN32__
    DEBUGF("dthread_signal_set: handle=%d", DTHREAD_EVENT(thr->iq_signal[0]));
    SetEvent(DTHREAD_EVENT(thr->iq_signal[0]));
    return 1;
#else
    DEBUGF("dthread_signal_set: fd=%d", DTHREAD_EVENT(thr->iq_signal[1]));
    return write(DTHREAD_EVENT(thr->iq_signal[1]), "!", 1);
#endif
}
예제 #2
0
파일: dthread.c 프로젝트: relabsoss/uart
// consume wakeup token
int dthread_signal_reset(dthread_t* thr)
{
#ifdef __WIN32__
    DEBUGF("dthread_signal_reset: handle=%d", DTHREAD_EVENT(thr->iq_signal[0]));
    ResetEvent(DTHREAD_EVENT(thr->iq_signal[0]));
    return 0;
#else
    {
	char buf[1];
	DEBUGF("dthread_signal_reset: fd=%d", DTHREAD_EVENT(thr->iq_signal[0]));
	return read(DTHREAD_EVENT(thr->iq_signal[0]), buf, 1);
    }
#endif
}
예제 #3
0
파일: uart_drv.c 프로젝트: Feuerlabs/uart
// NOTE: when SMP is enabled the messages go straight to the caller
// This code is here to allow non SMP emulator with the same code base.
static void uart_drv_ready_input(ErlDrvData d, ErlDrvEvent e)
{
    drv_ctx_t* ctx = (drv_ctx_t*) d;

    DEBUGF("uart_drv: ready_input called");

    if (ctx->self.iq_signal[0] == e) { // got input !
	dmessage_t* mp;

	DEBUGF("uart_drv: ready_input handle=%d", 
	       DTHREAD_EVENT(ctx->self.iq_signal[0]));

	if ((mp = dthread_recv(&ctx->self, NULL)) == NULL) {
	    DEBUGF("uart_drv: ready_input signaled with no event! handle=%d",
		   DTHREAD_EVENT(ctx->self.iq_signal[0]));
	    return;
	}

	switch(mp->cmd) {
	case DTHREAD_OUTPUT_TERM:
	    DEBUGF("uart_drv: ready_input (OUTPUT_TERM)");
	    driver_output_term(ctx->self.port, 
			       (ErlDrvTermData*) mp->buffer,
			       mp->used / sizeof(ErlDrvTermData));
	    break;
	case DTHREAD_SEND_TERM:
	    DEBUGF("uart_drv: ready_input (SEND_TERM)");
	    // dterm_dump(stderr, (ErlDrvTermData*) mp->buffer,
	    //   mp->used / sizeof(ErlDrvTermData));
	    driver_send_term(ctx->self.port, mp->to, /* orignal from ! */
			     (ErlDrvTermData*) mp->buffer,
			     mp->used / sizeof(ErlDrvTermData)); 
	    break;
	case DTHREAD_OUTPUT:
	    DEBUGF("uart_drv: ready_input (OUTPUT)");
	    driver_output(ctx->self.port, mp->buffer, mp->used);
	    break;
	default:
	    DEBUGF("uart_drv: read_input cmd=%d not matched",
		   mp->cmd);
	    break;
	}
	dmessage_free(mp);
    }
    else {
	DEBUGF("uart_drv: ready_input (NO MATCH)");
    }
}
예제 #4
0
파일: dthread.c 프로젝트: relabsoss/uart
void dthread_signal_select(dthread_t* thr, int on)
{
    DEBUGF("dthread_signal_select: fd=%d", 
	   DTHREAD_EVENT(thr->iq_signal[0]));
#ifdef __WIN32__
    driver_select(thr->port,thr->iq_signal[0],ERL_DRV_READ,on);
#else
    driver_select(thr->port,thr->iq_signal[0],ERL_DRV_READ,on);
#endif
}
예제 #5
0
파일: dthread.c 프로젝트: relabsoss/uart
void dthread_signal_finish(dthread_t* thr, int and_close)
{
    if (thr->iq_signal[0] != (ErlDrvEvent)DTHREAD_INVALID_EVENT) {
	if (and_close) {
	    DEBUGF("dthread_signal_finish: close iq_signal[0]=%d",
		   DTHREAD_EVENT(thr->iq_signal[0]));
	    DTHREAD_CLOSE_EVENT(thr->iq_signal[0]);
	}
	thr->iq_signal[0] = (ErlDrvEvent)DTHREAD_INVALID_EVENT;
    }

    if (thr->iq_signal[1] != (ErlDrvEvent)DTHREAD_INVALID_EVENT) {
	if (and_close) {
	    DEBUGF("dthread_signal_finish: iq_signal[1]=%d",
		   DTHREAD_EVENT(thr->iq_signal[1]));
	    DTHREAD_CLOSE_EVENT(thr->iq_signal[1]);
	}
	thr->iq_signal[1] = (ErlDrvEvent)DTHREAD_INVALID_EVENT;
    }
}
예제 #6
0
파일: dthread.c 프로젝트: relabsoss/uart
// 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;
}
예제 #7
0
파일: uart_drv.c 프로젝트: Feuerlabs/uart
static void uart_drv_stop_select(ErlDrvEvent event, void* arg)
{
    (void) arg;
    DEBUGF("uart_drv: stop_select event=%d", DTHREAD_EVENT(event));
    dthread_event_close(event);
}
예제 #8
0
파일: dthread.c 프로젝트: relabsoss/uart
int dthread_poll(dthread_t* thr, dthread_poll_event_t* events, size_t* nevents, 
		 int timeout)
{
    struct timeval tm;
    struct timeval* tp;
    fd_set readfds;
    fd_set writefds;
    fd_set errorfds;
    int fd,nfds = 0;
    int ready;
    int i,n,iq_len=0;

    if (timeout < 0)
	tp = NULL;
    else {
	tm.tv_sec = timeout / 1000;
	tm.tv_usec = (timeout - tm.tv_sec*1000) * 1000;
	tp = &tm;
    }
    FD_ZERO(&readfds);
    FD_ZERO(&writefds);
    FD_ZERO(&errorfds);

    if ((fd = DTHREAD_EVENT(thr->iq_signal[0])) >= 0) {
	FD_SET(fd, &readfds);
	FD_SET(fd, &errorfds);
	DEBUGF("FD_SET: iq_signal[0] = %d", fd);
	if (fd > nfds) nfds = fd;
    }

    if (events && nevents && *nevents) {
	n = (int) (*nevents);
	for (i = 0; i < n; i++) {
	    events[i].revents = 0;  // clear here in case of timeout etc
	    if (events[i].events) {
		fd = DTHREAD_EVENT(events[i].event);
		if (events[i].events & ERL_DRV_READ) {
		    FD_SET(fd, &readfds);
		    FD_SET(fd, &errorfds);
		}
		if (events[i].events & ERL_DRV_WRITE)
		    FD_SET(fd, &writefds);
		if (fd > nfds) nfds = fd;
	    }
	}
    }

    DEBUGF("select nfds=%d, tp=%p", nfds, tp);
    ready = select(nfds+1, &readfds, &writefds, &errorfds, tp);
    DEBUGF("select result r=%d", ready);
    if (ready <= 0) {
	if (nevents)
	    *nevents = 0;
	return ready;
    }

    // check queue !
    fd = DTHREAD_EVENT(thr->iq_signal[0]);
    if (FD_ISSET(fd, &readfds)) {
	erl_drv_mutex_lock(thr->iq_mtx);
	iq_len = thr->iq_len;
	erl_drv_mutex_unlock(thr->iq_mtx);
	ready--;
    }

    // check io events
    if (ready && events && nevents && *nevents) {
	size_t nready = 0;
	n = (int) (*nevents);
	for (i = 0; ready && (i < n); i++) {
	    size_t fd_ready = 0;
	    fd = DTHREAD_EVENT(events[i].event);
	    if (FD_ISSET(fd, &readfds) || FD_ISSET(fd, &errorfds)) {
		events[i].revents |= ERL_DRV_READ;
		if (FD_ISSET(fd, &errorfds))
		    events[i].revents |= ERL_DRV_EXCEP;
		fd_ready = 1;
	    }
	    if (FD_ISSET(fd, &writefds)) {
		events[i].revents |= ERL_DRV_WRITE; 
		fd_ready = 1;
	    }
	    nready += fd_ready;
	    ready--;
	}
	*nevents = nready;
    }
    return iq_len;
}
예제 #9
0
파일: dthread.c 프로젝트: relabsoss/uart
int dthread_poll(dthread_t* thr, dthread_poll_event_t* events, size_t* nevents, 
		 int timeout)
{
    HANDLE handles[MAXIMUM_WAIT_OBJECTS];
    int    eindex[MAXIMUM_WAIT_OBJECTS];
    DWORD  nCount = 0;
    DWORD  iq_len = 0;
    DWORD  nready = 0;
    DWORD  dwMilliseconds;
    DWORD  res;
    int    i,n;

    if (timeout < 0)
	dwMilliseconds = INFINITE;
    else
	dwMilliseconds = (DWORD) timeout;

    // install handles to wait for
    if (DTHREAD_EVENT(thr->iq_signal[0]) != DTHREAD_INVALID_EVENT) {
	eindex[nCount] = -1;  // -1 == signal queue event
	handles[nCount] = DTHREAD_EVENT(thr->iq_signal[0]);
	nCount++;
    }

    if (events && nevents && *nevents) {
	n = (DWORD) (*nevents);
	for (i = 0; (nCount < MAXIMUM_WAIT_OBJECTS) && (i < n); i++) {
	    events[i].revents = 0; // clear here in case of timeout etc
	    if (events[i].events) {
		eindex[nCount]  = i;  // index in event array
		handles[nCount] = DTHREAD_EVENT(events[i].event);
		nCount++;
	    }
	}
    }

    DEBUGF("WaitForMultipleObjects nCount=%d, timeout=%d", nCount, 
	   dwMilliseconds);
    // wait for first event that is signaled
    res = WaitForMultipleObjects(nCount, handles, FALSE, dwMilliseconds);
    DEBUGF("WaitForMultipleObjects result=%d", res);
    
    if (res == WAIT_TIMEOUT)
	return 0;
    else if (res == WAIT_FAILED)
	return -1;
    else if ((res >= WAIT_OBJECT_0) && (res < (WAIT_OBJECT_0+nCount))) {
	DWORD j = res - WAIT_OBJECT_0;
	
	if ((i = eindex[j]) < 0) {
	    erl_drv_mutex_lock(thr->iq_mtx);
	    iq_len = thr->iq_len;
	    erl_drv_mutex_unlock(thr->iq_mtx);
	}
	else if (events != NULL) {
	    events[i].revents |= ERL_DRV_READ;  // event is ready
	    nready++;
	}
	j++;

	// must scan rest of the events as well, else starvation may occure 
	while (j < nCount) {
	    if (WaitForSingleObject(handles[j], 0) == WAIT_OBJECT_0) {
		if ((i = eindex[j]) < 0) {
		    erl_drv_mutex_lock(thr->iq_mtx);
		    iq_len = thr->iq_len;
		    erl_drv_mutex_unlock(thr->iq_mtx);
		}
		else if (events != NULL) {
		    events[i].revents |= ERL_DRV_READ;  // event is ready
		    nready++;
		}		
	    }
	    j++;
	}
    }
    if (nevents)
	*nevents = nready;
    return iq_len;
}
예제 #10
0
파일: dthread.c 프로젝트: relabsoss/uart
extern void dthread_event_close(ErlDrvEvent event)
{
    INFOF("event_close: %d", DTHREAD_EVENT(event));
    DTHREAD_CLOSE_EVENT(event);
}