From 7f47a92573929841c178ea208047915845283f70 Mon Sep 17 00:00:00 2001 From: hyung-hwan Date: Tue, 2 Feb 2016 07:51:17 +0000 Subject: [PATCH] added stio_ruindev() and improved half-open state handling for a tcp device --- stio/lib/main.c | 19 ++- stio/lib/stio-prv.h | 4 +- stio/lib/stio-tcp.c | 15 +- stio/lib/stio.c | 324 +++++++++++++++++++++++++++----------------- stio/lib/stio.h | 67 +++++---- 5 files changed, 263 insertions(+), 166 deletions(-) diff --git a/stio/lib/main.c b/stio/lib/main.c index 96a44dc..ed80beb 100644 --- a/stio/lib/main.c +++ b/stio/lib/main.c @@ -107,7 +107,14 @@ static int tcp_on_sent (stio_dev_tcp_t* tcp, void* sendctx) static int tcp_on_recv (stio_dev_tcp_t* tcp, const void* buf, stio_len_t len) { - return stio_dev_tcp_send (tcp, "HELLO", 5, STIO_NULL); +int n; +static char a ='A'; +char* xxx = malloc (1000000); +memset (xxx, a++ ,1000000); + //return stio_dev_tcp_send (tcp, "HELLO", 5, STIO_NULL); + n = stio_dev_tcp_send (tcp, xxx, 1000000, STIO_NULL); +free (xxx); +return n; } static stio_t* g_stio; @@ -143,13 +150,13 @@ int main () sigact.sa_handler = handle_signal; sigaction (SIGINT, &sigact, STIO_NULL); - //STIO_MEMSET (&sigact, 0, STIO_SIZEOF(sigact)); - //sigact.sa_handler = SIG_IGN; - //sigaction (SIGPIPE, &sigact, STIO_NULL); + memset (&sigact, 0, STIO_SIZEOF(sigact)); + sigact.sa_handler = SIG_IGN; + sigaction (SIGPIPE, &sigact, STIO_NULL); - memset (&sin, 0, STIO_SIZEOF(sin)); + /*memset (&sin, 0, STIO_SIZEOF(sin)); sin.sin_family = AF_INET; - sin.sin_port = htons(1234); + sin.sin_port = htons(1234); */ /* udp = (stio_dev_udp_t*)stio_makedev (stio, STIO_SIZEOF(*udp), &udp_mth, &udp_evcb, &sin); if (!udp) diff --git a/stio/lib/stio-prv.h b/stio/lib/stio-prv.h index 75a93e3..c3e09fe 100644 --- a/stio/lib/stio-prv.h +++ b/stio/lib/stio-prv.h @@ -68,7 +68,9 @@ struct stio_t { stio_dev_t* head; stio_dev_t* tail; - } dev; + } dev; /* normal devices */ + + stio_dev_t* rdev; /* ruined device list - singly linked list */ stio_uint8_t bigbuf[65535]; /* TODO: make this dynamic depending on devices added. device may indicate a buffer size required??? */ diff --git a/stio/lib/stio-tcp.c b/stio/lib/stio-tcp.c index 9b4c9e9..2fda05f 100644 --- a/stio/lib/stio-tcp.c +++ b/stio/lib/stio-tcp.c @@ -165,10 +165,6 @@ static void tmr_connect_handle (stio_t* stio, const stio_ntime_t* now, stio_tmrj * doesn't need to be deleted when it gets connected for this check * here. this libarary, however, deletes the job when it gets * connected. */ -/* - if (tcp->on_disconnected) tcp->on_disconnected (tcp); - tcp->state &= ~STIO_DEV_TCP_CONNECTING; -*/ stio_dev_tcp_kill (tcp); } } @@ -241,7 +237,7 @@ static int tcp_ioctl (stio_dev_t* dev, int cmd, void* arg) { if (errno == EINPROGRESS || errno == EWOULDBLOCK) { - if (stio_dev_event ((stio_dev_t*)tcp, STIO_DEV_EVENT_UPD, STIO_DEV_EVENT_IN | STIO_DEV_EVENT_OUT) >= 0) + if (stio_dev_watch ((stio_dev_t*)tcp, STIO_DEV_WATCH_UPDATE, STIO_DEV_EVENT_IN | STIO_DEV_EVENT_OUT) >= 0) { stio_tmrjob_t tmrjob; @@ -262,7 +258,7 @@ static int tcp_ioctl (stio_dev_t* dev, int cmd, void* arg) tcp->tmridx_connect = stio_instmrjob (tcp->stio, &tmrjob); if (tcp->tmridx_connect == STIO_TMRIDX_INVALID) { - stio_dev_event ((stio_dev_t*)tcp, STIO_DEV_EVENT_UPD, STIO_DEV_EVENT_IN); + stio_dev_watch ((stio_dev_t*)tcp, STIO_DEV_WATCH_UPDATE, STIO_DEV_EVENT_IN); /* event manipulation failure can't be handled properly. so ignore it */ return -1; } @@ -386,7 +382,6 @@ printf ("TCP READY...%p\n", dev); STIO_ASSERT (!(tcp->state & STIO_DEV_TCP_CONNECTED)); -printf ("XXXXXXXXXXXXXXX CONNECTED...\n"); len = STIO_SIZEOF(errcode); if (getsockopt (tcp->sck, SOL_SOCKET, SO_ERROR, (char*)&errcode, &len) == -1) { @@ -398,9 +393,9 @@ printf ("XXXXXXXXXXXXXXX CONNECTED...\n"); tcp->state &= ~STIO_DEV_TCP_CONNECTING; tcp->state |= STIO_DEV_TCP_CONNECTED; - if (stio_dev_event ((stio_dev_t*)tcp, STIO_DEV_EVENT_UPD, STIO_DEV_EVENT_IN) <= -1) + if (stio_dev_watch ((stio_dev_t*)tcp, STIO_DEV_WATCH_UPDATE, STIO_DEV_EVENT_IN) <= -1) { -printf ("CAANOT MANIPULTE EVENT ...\n"); +printf ("CAANOT MANIPULTE WATCHER ...\n"); return -1; } @@ -464,7 +459,7 @@ printf ("CAANOT MANIPULTE EVENT ...\n"); /* addr is the address of the peer */ /* local addresss is inherited from the server */ - clitcp = (stio_dev_tcp_t*)stio_makedev (tcp->stio, STIO_SIZEOF(*tcp), &tcp_acc_mth, tcp->evcb, &clisck); + clitcp = (stio_dev_tcp_t*)stio_makedev (tcp->stio, STIO_SIZEOF(*tcp), &tcp_acc_mth, tcp->dev_evcb, &clisck); if (!clitcp) { close (clisck); diff --git a/stio/lib/stio.c b/stio/lib/stio.c index e7a61fc..561a284 100644 --- a/stio/lib/stio.c +++ b/stio/lib/stio.c @@ -123,43 +123,41 @@ stio_dev_t* stio_makedev (stio_t* stio, stio_size_t dev_size, stio_dev_mth_t* de STIO_MEMSET (dev, 0, dev_size); dev->stio = stio; - dev->mth = dev_mth; - dev->evcb = dev_evcb; + /* default capability. dev->dev_mth->make() can change this. + * stio_dev_watch() is affected by the capability change. */ + dev->dev_capa = STIO_DEV_CAPA_IN | STIO_DEV_CAPA_OUT; + dev->dev_mth = dev_mth; + dev->dev_evcb = dev_evcb; STIO_WQ_INIT(&dev->wq); /* call the callback function first */ stio->errnum = STIO_ENOERR; - if (dev->mth->make (dev, make_ctx) <= -1) + if (dev->dev_mth->make (dev, make_ctx) <= -1) { if (stio->errnum == STIO_ENOERR) stio->errnum = STIO_EDEVMAKE; goto oops; } - /* ------------------------------------ */ +#if defined(_WIN32) + if (CreateIoCompletionPort ((HANDLE)dev->dev_mth->getsyshnd(dev), stio->iocp, STIO_IOCP_KEY, 0) == NULL) { - #if defined(_WIN32) - if (CreateIoCompletionPort ((HANDLE)dev->mth->getsyshnd(dev), stio->iocp, STIO_IOCP_KEY, 0) == NULL) - { - /* TODO: set errnum from GetLastError()... */ - goto oops_after_make; - } - - #else - if (stio_dev_event (dev, STIO_DEV_EVENT_ADD, STIO_DEV_EVENT_IN) <= -1) goto oops_after_make; - #endif + /* TODO: set errnum from GetLastError()... */ + goto oops_after_make; } - /* ------------------------------------ */ +#else + if (stio_dev_watch (dev, STIO_DEV_WATCH_START, STIO_DEV_EVENT_IN) <= -1) goto oops_after_make; +#endif /* and place the new dev at the back */ - if (stio->dev.tail) stio->dev.tail->next = dev; + if (stio->dev.tail) stio->dev.tail->dev_next = dev; else stio->dev.head = dev; - dev->prev = stio->dev.tail; + dev->dev_prev = stio->dev.tail; stio->dev.tail = dev; return dev; oops_after_make: - dev->mth->kill (dev); + dev->dev_mth->kill (dev); oops: STIO_MMGR_FREE (stio->mmgr, dev); return STIO_NULL; @@ -175,31 +173,56 @@ void stio_killdev (stio_t* stio, stio_dev_t* dev) stio_wq_t* wq; wq = STIO_WQ_HEAD(&dev->wq); -printf ("DELETING UNSENT REQUETS...%p\n", wq); STIO_WQ_DEQ (&dev->wq); STIO_MMGR_FREE (stio->mmgr, wq); } /* delink the dev object */ - if (dev->prev) - dev->prev->next = dev->next; - else - stio->dev.head = dev->next; + if (!(dev->dev_capa & STIO_DEV_CAPA_RUINED)) + { + if (dev->dev_prev) + dev->dev_prev->dev_next = dev->dev_next; + else + stio->dev.head = dev->dev_next; - if (dev->next) - dev->next->prev = dev->prev; - else - stio->dev.tail = dev->prev; + if (dev->dev_next) + dev->dev_next->dev_prev = dev->dev_prev; + else + stio->dev.tail = dev->dev_prev; + } - stio_dev_event (dev, STIO_DEV_EVENT_DEL, 0); + stio_dev_watch (dev, STIO_DEV_WATCH_STOP, 0); /* and call the callback function */ - dev->mth->kill (dev); + dev->dev_mth->kill (dev); STIO_MMGR_FREE (stio->mmgr, dev); } +void stio_ruindev (stio_t* stio, stio_dev_t* dev) +{ + if (!(dev->dev_capa & STIO_DEV_CAPA_RUINED)) + { + /* delink the dev object from the device list */ + if (dev->dev_prev) + dev->dev_prev->dev_next = dev->dev_next; + else + stio->dev.head = dev->dev_next; + if (dev->dev_next) + dev->dev_next->dev_prev = dev->dev_prev; + else + stio->dev.tail = dev->dev_prev; + + /* place it at the beginning of the ruined device list */ + dev->dev_prev = STIO_NULL; + dev->dev_next = stio->rdev; + stio->rdev = dev; + + dev->dev_capa |= STIO_DEV_CAPA_RUINED; + } +} + int stio_prologue (stio_t* stio) { /* TODO: */ @@ -215,6 +238,7 @@ int stio_exec (stio_t* stio) { stio_ntime_t tmout; + #if defined(_WIN32) ULONG nentries, i; #else @@ -260,31 +284,42 @@ int stio_exec (stio_t* stio) /* TODO: merge events??? for the same descriptor */ for (i = 0; i < nentries; i++) { - stio_dev_t* dev = stio->revs[i].data.ptr; + stio_dev_t* dev; - if (dev->evcb->ready) + dev = stio->revs[i].data.ptr; + + if (dev->dev_evcb->ready) { int x, events = 0; if (stio->revs[i].events & EPOLLERR) events |= STIO_DEV_EVENT_ERR; if (stio->revs[i].events & EPOLLHUP) events |= STIO_DEV_EVENT_HUP; - #if defined(EPOLLRDHUP) - /* treat it the same way as EPOLLHUP */ - if (stio->revs[i].events & EPOLLRDHUP) events |= STIO_DEV_EVENT_HUP; - #endif if (stio->revs[i].events & EPOLLIN) events |= STIO_DEV_EVENT_IN; if (stio->revs[i].events & EPOLLOUT) events |= STIO_DEV_EVENT_OUT; if (stio->revs[i].events & EPOLLPRI) events |= STIO_DEV_EVENT_PRI; + #if defined(EPOLLRDHUP) + /* interprete EPOLLRDHUP the same way as EPOLLHUP. + * + * when EPOLLRDHUP is set, EPOLLIN or EPOLLPRI or both are + * assumed to be set as EPOLLRDHUP is requested only if + * STIO_DEV_WATCH_IN is set for stio_dev_watch(). + * in linux, when EPOLLRDHUP is set, EPOLLIN is set together + * if it's requested together. it seems to be safe to have + * the following assertion. however, let me commect it out + * in case the assumption above is not right. + * STIO_ASSERT (events & (STIO_DEV_EVENT_IN | STIO_DEV_EVENT_PRI)); + */ + if (stio->revs[i].events & EPOLLRDHUP) events |= STIO_DEV_EVENT_HUP; + #endif /* return value of ready() * <= -1 - failure. kill the device. * == 0 - ok. but don't invoke recv() or send(). * >= 1 - everything is ok. */ -/* TODO: can the revs array contain the same file descriptor again??? */ - if ((x = dev->evcb->ready (dev, events)) <= -1) + if ((x = dev->dev_evcb->ready (dev, events)) <= -1) { - stio_killdev (stio, dev); + stio_ruindev (stio, dev); dev = STIO_NULL; } else if (x >= 1) @@ -294,14 +329,12 @@ int stio_exec (stio_t* stio) } else { - int dev_eof; - invoke_evcb: - - dev_eof = 0; if (dev && stio->revs[i].events & EPOLLPRI) { /* urgent data */ +/* TODO: urgent data.... */ + /*x = dev->dev_mth->urgrecv (dev, stio->bugbuf, &len);*/ printf ("has urgent data...\n"); } @@ -315,35 +348,55 @@ int stio_exec (stio_t* stio) while (1) { len = STIO_COUNTOF(stio->bigbuf); - x = dev->mth->recv (dev, stio->bigbuf, &len); + x = dev->dev_mth->recv (dev, stio->bigbuf, &len); - printf ("DATA...recv %d length %d\n", (int)x, len); if (x <= -1) { - /*TODO: what to do? killdev? how to indicate an error? call on_recv? with error indicator?? */ - stio_killdev (stio, dev); + stio_ruindev (stio, dev); dev = STIO_NULL; break; } else if (x == 0) { - /* no data is available */ + /* no data is available - EWOULDBLOCK or something similar */ break; } else if (x >= 1) { if (len <= 0) { - /* EOF received. delay killing until output has been handled */ - dev_eof = 1; + /* EOF received. delay killing until output has been handled. */ + if (STIO_WQ_ISEMPTY(&dev->wq)) + { + /* no pending writes - ruin the device to kill it eventually */ + stio_ruindev (stio, dev); + /* don't set 'dev' to STIO_NULL so that + * output handling can kick in if EPOLLOUT is set */ + } + else + { + /* it might be in a half-open state */ + dev->dev_capa &= ~(STIO_DEV_CAPA_IN | STIO_DEV_CAPA_PRI); + + /* disable the input watching */ + if (stio_dev_watch (dev, STIO_DEV_WATCH_UPDATE, STIO_DEV_EVENT_OUT) <= -1) + { + stio_ruindev (stio, dev); + dev = STIO_NULL; + } + } + break; } else { + /* TODO: for a stream device, merge received data if bigbuf isn't full and fire the on_recv callback + * when x == 0 or <= -1. you can */ + /* data available */ - if (dev->evcb->on_recv (dev, stio->bigbuf, len) <= -1) + if (dev->dev_evcb->on_recv (dev, stio->bigbuf, len) <= -1) { - stio_killdev (stio, dev); + stio_ruindev (stio, dev); dev = STIO_NULL; break; } @@ -368,7 +421,7 @@ int stio_exec (stio_t* stio) send_leftover: ulen = urem; - x = dev->mth->send (dev, uptr, &ulen); + x = dev->dev_mth->send (dev, uptr, &ulen); if (x <= -1) { /* TODO: error handling? call callback? or what? */ @@ -393,7 +446,7 @@ int stio_exec (stio_t* stio) int y; STIO_WQ_UNLINK (q); /* STIO_WQ_DEQ(&dev->wq); */ - y = dev->evcb->on_sent (dev, q->ctx); + y = dev->dev_evcb->on_sent (dev, q->ctx); STIO_MMGR_FREE (dev->stio->mmgr, q); if (y <= -1) @@ -411,24 +464,35 @@ int stio_exec (stio_t* stio) { /* no pending request to write. * watch input only. disable output watching */ - if (stio_dev_event (dev, STIO_DEV_EVENT_UPD, STIO_DEV_EVENT_IN) <= -1) + if (dev->dev_capa & STIO_DEV_CAPA_IN) { - /* TODO: call an error handler??? */ - stio_killdev (stio, dev); + if (stio_dev_watch (dev, STIO_DEV_WATCH_UPDATE, STIO_DEV_EVENT_IN) <= -1) + { + stio_ruindev (stio, dev); + dev = STIO_NULL; + } + } + else + { + /* the device is not capable of reading. + * finish the device */ + stio_ruindev (stio, dev); dev = STIO_NULL; } } } - - if (dev && dev_eof) - { - /* handled delayed device killing */ - stio_killdev (stio, dev); - dev = STIO_NULL; - } } } + /* kill all ruined devices */ + while (stio->rdev) + { + stio_dev_t* next; + next = stio->rdev->dev_next; + stio_killdev (stio, stio->rdev); + stio->rdev = next; + } + #endif return 0; @@ -456,44 +520,58 @@ int stio_loop (stio_t* stio) return 0; } - int stio_dev_ioctl (stio_dev_t* dev, int cmd, void* arg) { - if (dev->mth->ioctl) return dev->mth->ioctl (dev, cmd, arg); + if (dev->dev_mth->ioctl) return dev->dev_mth->ioctl (dev, cmd, arg); dev->stio->errnum = STIO_ENOSUP; /* TODO: different error code ? */ return -1; } -int stio_dev_event (stio_dev_t* dev, stio_dev_event_cmd_t cmd, int flags) +int stio_dev_watch (stio_dev_t* dev, stio_dev_watch_cmd_t cmd, int events) { -#if defined(_WIN32) - - /* TODO */ -#else struct epoll_event ev; int epoll_op; + /* this function honors STIO_DEV_EVENT_IN and STIO_DEV_EVENT_OUT only + * as valid input event bits. it intends to provide simple abstraction + * by reducing the variety of event bits that the caller has to handle. */ ev.events = EPOLLHUP | EPOLLERR; -#if defined(EPOLLRDHUP) - ev.events |= EPOLLRDHUP; -#endif - if (flags & STIO_DEV_EVENT_IN) ev.events |= EPOLLIN; - if (flags & STIO_DEV_EVENT_OUT) ev.events |= EPOLLOUT; - if (flags & STIO_DEV_EVENT_PRI) ev.events |= EPOLLPRI; + if (events & STIO_DEV_EVENT_IN) + { + if (dev->dev_capa & STIO_DEV_CAPA_IN) + { + ev.events |= EPOLLIN; + #if defined(EPOLLRDHUP) + ev.events |= EPOLLRDHUP; + #endif + } + if (dev->dev_capa & STIO_DEV_CAPA_PRI) + { + ev.events |= EPOLLPRI; + #if defined(EPOLLRDHUP) + ev.events |= EPOLLRDHUP; + #endif + } + } + + if (events & STIO_DEV_EVENT_OUT) + { + if (dev->dev_capa & STIO_DEV_CAPA_OUT) ev.events |= EPOLLOUT; + } + ev.data.ptr = dev; - switch (cmd) { - case STIO_DEV_EVENT_ADD: + case STIO_DEV_WATCH_START: epoll_op = EPOLL_CTL_ADD; break; - case STIO_DEV_EVENT_UPD: + case STIO_DEV_WATCH_UPDATE: epoll_op = EPOLL_CTL_MOD; break; - case STIO_DEV_EVENT_DEL: + case STIO_DEV_WATCH_STOP: epoll_op = EPOLL_CTL_DEL; break; @@ -502,66 +580,40 @@ int stio_dev_event (stio_dev_t* dev, stio_dev_event_cmd_t cmd, int flags) return -1; } - if (epoll_ctl (dev->stio->mux, epoll_op, dev->mth->getsyshnd(dev), &ev) == -1) + if (epoll_ctl (dev->stio->mux, epoll_op, dev->dev_mth->getsyshnd(dev), &ev) == -1) { dev->stio->errnum = stio_syserrtoerrnum(errno); return -1; } return 0; -#endif } int stio_dev_send (stio_dev_t* dev, const void* data, stio_len_t len, void* sendctx) { const stio_uint8_t* uptr; stio_len_t urem, ulen; - int x; + stio_wq_t* q; + int x, wq_empty; + + if (!(dev->dev_capa & STIO_DEV_CAPA_OUT)) + { + dev->stio->errnum = STIO_ENOCAPA; + return -1; + } uptr = data; urem = len; + wq_empty = STIO_WQ_ISEMPTY(&dev->wq); + if (!wq_empty) goto enqueue_data; + while (urem > 0) { ulen = urem; - x = dev->mth->send (dev, data, &ulen); - if (x <= -1) - { - return -1; - } - else if (x == 0) - { - stio_wq_t* q; - int wq_empty; - - /* queue the uremaining data*/ - wq_empty = STIO_WQ_ISEMPTY(&dev->wq); - - q = (stio_wq_t*)STIO_MMGR_ALLOC (dev->stio->mmgr, STIO_SIZEOF(*q) + urem); - if (!q) - { - dev->stio->errnum = STIO_ENOMEM; - return -1; - } - - q->ctx = sendctx; - q->ptr = (stio_uint8_t*)(q + 1); - q->len = urem; - STIO_MEMCPY (q->ptr, uptr, urem); - - STIO_WQ_ENQ (&dev->wq, q); - if (wq_empty) - { - if (stio_dev_event (dev, STIO_DEV_EVENT_UPD, STIO_DEV_EVENT_IN | STIO_DEV_EVENT_OUT) <= -1) - { - STIO_WQ_UNLINK (q); /* unlink the ENQed item */ - STIO_MMGR_FREE (dev->stio->mmgr, q); - return -1; - } - } - - return 0; - } + x = dev->dev_mth->send (dev, data, &ulen); + if (x <= -1) return -1; + else if (x == 0) goto enqueue_data; /* enqueue remaining data */ else { urem -= ulen; @@ -569,11 +621,37 @@ int stio_dev_send (stio_dev_t* dev, const void* data, stio_len_t len, void* send } } - dev->evcb->on_sent (dev, sendctx); + dev->dev_evcb->on_sent (dev, sendctx); + return 0; + +enqueue_data: + /* queue the remaining data*/ + q = (stio_wq_t*)STIO_MMGR_ALLOC (dev->stio->mmgr, STIO_SIZEOF(*q) + urem); + if (!q) + { + dev->stio->errnum = STIO_ENOMEM; + return -1; + } + + q->ctx = sendctx; + q->ptr = (stio_uint8_t*)(q + 1); + q->len = urem; + STIO_MEMCPY (q->ptr, uptr, urem); + + STIO_WQ_ENQ (&dev->wq, q); + if (wq_empty) + { + if (stio_dev_watch (dev, STIO_DEV_WATCH_UPDATE, STIO_DEV_EVENT_IN | STIO_DEV_EVENT_OUT) <= -1) + { + STIO_WQ_UNLINK (q); /* unlink the ENQed item */ + STIO_MMGR_FREE (dev->stio->mmgr, q); + return -1; + } + } + return 0; } - stio_errnum_t stio_syserrtoerrnum (int no) { switch (no) diff --git a/stio/lib/stio.h b/stio/lib/stio.h index 9fbf367..e947324 100644 --- a/stio/lib/stio.h +++ b/stio/lib/stio.h @@ -102,11 +102,12 @@ enum stio_errnum_t STIO_ENOMEM, STIO_EINVAL, STIO_ENOENT, - STIO_ENOSUP, /* not supported */ + STIO_ENOSUP, /* not supported */ STIO_EMFILE, STIO_ENFILE, - STIO_ECONRF, /* connection refused */ - STIO_ECONRS, /* connection reset */ + STIO_ECONRF, /* connection refused */ + STIO_ECONRS, /* connection reset */ + STIO_ENOCAPA, /* no capability */ STIO_EDEVMAKE, STIO_EDEVERR, @@ -127,12 +128,6 @@ struct stio_dev_mth_t void (*kill) (stio_dev_t* dev); /* mandatory. called in stio_killdev(). called in stio_makedev() upon failure after make() success */ /* ------------------------------------------------------------------ */ -#if 0 -/* TODO: countsyshnds() if the device has multiple handles. - * getsyshnd() to accept the handle id between 0 and countsysnhnds() - 1 - */ - int (*countsyshnds) (stio_dev_t* dev); /* optional */ -#endif stio_syshnd_t (*getsyshnd) (stio_dev_t* dev); /* mandatory. called in stio_makedev() after successful make() */ /* ------------------------------------------------------------------ */ @@ -216,35 +211,49 @@ struct stio_wq_t #define STIO_WQ_DEQ(wq) STIO_WQ_UNLINK(STIO_WQ_HEAD(wq)) #define STIO_DEV_HEADERS \ - stio_t* stio; \ - stio_dev_mth_t* mth; \ - stio_dev_evcb_t* evcb; \ - stio_wq_t wq; \ - stio_dev_t* prev; \ - stio_dev_t* next + stio_t* stio; \ + int dev_capa; \ + stio_dev_mth_t* dev_mth; \ + stio_dev_evcb_t* dev_evcb; \ + stio_wq_t wq; \ + stio_dev_t* dev_prev; \ + stio_dev_t* dev_next struct stio_dev_t { STIO_DEV_HEADERS; }; -enum stio_dev_event_cmd_t +enum stio_dev_capa_t { - STIO_DEV_EVENT_ADD, - STIO_DEV_EVENT_UPD, - STIO_DEV_EVENT_DEL -}; -typedef enum stio_dev_event_cmd_t stio_dev_event_cmd_t; + STIO_DEV_CAPA_IN = (1 << 0), + STIO_DEV_CAPA_OUT = (1 << 1), + STIO_DEV_CAPA_PRI = (1 << 2), + STIO_DEV_CAPA_STREAM = (1 << 3), -enum stio_dev_event_flag_t + /* internal use only. never set this bit to the dev_capa field */ + STIO_DEV_CAPA_RUINED = (1 << 15) +}; +typedef enum stio_dev_capa_t stio_dev_capa_t; + +enum stio_dev_watch_cmd_t +{ + STIO_DEV_WATCH_START, + STIO_DEV_WATCH_UPDATE, + STIO_DEV_WATCH_STOP +}; +typedef enum stio_dev_watch_cmd_t stio_dev_watch_cmd_t; + +enum stio_dev_event_t { STIO_DEV_EVENT_IN = (1 << 0), STIO_DEV_EVENT_OUT = (1 << 1), + STIO_DEV_EVENT_PRI = (1 << 2), STIO_DEV_EVENT_HUP = (1 << 3), STIO_DEV_EVENT_ERR = (1 << 4) }; -typedef enum stio_dev_event_flag_t stio_dev_event_flag_t; +typedef enum stio_dev_event_t stio_dev_event_t; typedef struct stio_tmrjob_t stio_tmrjob_t; @@ -313,16 +322,22 @@ STIO_EXPORT void stio_killdev ( stio_dev_t* dev ); +STIO_EXPORT void stio_ruindev ( + stio_t* stio, + stio_dev_t* dev +); + STIO_EXPORT int stio_dev_ioctl ( stio_dev_t* dev, int cmd, void* arg ); -STIO_EXPORT int stio_dev_event ( +STIO_EXPORT int stio_dev_watch ( stio_dev_t* dev, - stio_dev_event_cmd_t cmd, - int flags + stio_dev_watch_cmd_t cmd, + /** 0 or bitwise-ORed of #STIO_DEV_EVENT_IN and #STIO_DEV_EVENT_OUT */ + int events ); STIO_EXPORT int stio_dev_send (