queue.c - quark - quark web server
 (HTM) git clone git://git.suckless.org/quark
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) LICENSE
       ---
       queue.c (3653B)
       ---
            1 /* See LICENSE file for copyright and license details. */
            2 #include <stddef.h>
            3 
            4 #ifdef __linux__
            5         #include <sys/epoll.h>
            6 #else
            7         #include <sys/types.h>
            8         #include <sys/event.h>
            9         #include <sys/time.h>
           10 #endif
           11 
           12 #include "queue.h"
           13 #include "util.h"
           14 
           15 int
           16 queue_create(void)
           17 {
           18         int qfd;
           19 
           20         #ifdef __linux__
           21                 if ((qfd = epoll_create1(0)) < 0) {
           22                         warn("epoll_create1:");
           23                 }
           24         #else
           25                 if ((qfd = kqueue()) < 0) {
           26                         warn("kqueue:");
           27                 }
           28         #endif
           29 
           30         return qfd;
           31 }
           32 
           33 int
           34 queue_add_fd(int qfd, int fd, enum queue_event_type t, int shared,
           35              const void *data)
           36 {
           37         #ifdef __linux__
           38                 struct epoll_event e;
           39 
           40                 /* set event flag */
           41                 if (shared) {
           42                         /*
           43                          * if the fd is shared, "exclusive" is the only
           44                          * way to avoid spurious wakeups and "blocking"
           45                          * accept()'s.
           46                          */
           47                         e.events = EPOLLEXCLUSIVE;
           48                 } else {
           49                         /*
           50                          * if we have the fd for ourselves (i.e. only
           51                          * within the thread), we want to be
           52                          * edge-triggered, as our logic makes sure
           53                          * that the buffers are drained when we return
           54                          * to epoll_wait()
           55                          */
           56                         e.events = EPOLLET;
           57                 }
           58 
           59                 switch (t) {
           60                 case QUEUE_EVENT_IN:
           61                         e.events |= EPOLLIN;
           62                         break;
           63                 case QUEUE_EVENT_OUT:
           64                         e.events |= EPOLLOUT;
           65                         break;
           66                 }
           67 
           68                 /* set data pointer */
           69                 e.data.ptr = (void *)data;
           70 
           71                 /* register fd in the interest list */
           72                 if (epoll_ctl(qfd, EPOLL_CTL_ADD, fd, &e) < 0) {
           73                         warn("epoll_ctl:");
           74                         return -1;
           75                 }
           76         #else
           77                 struct kevent e;
           78                 int events;
           79 
           80                 /* prepare event flag */
           81                 events = (shared) ? 0 : EV_CLEAR;
           82 
           83                 switch (t) {
           84                 case QUEUE_EVENT_IN:
           85                         events |= EVFILT_READ;
           86                         break;
           87                 case QUEUE_EVENT_OUT:
           88                         events |= EVFILT_WRITE;
           89                         break;
           90                 }
           91 
           92                 EV_SET(&e, fd, events, EV_ADD, 0, 0, (void *)data);
           93 
           94                 if (kevent(qfd, &e, 1, NULL, 0, NULL) < 0) {
           95                         warn("kevent:");
           96                         return -1;
           97                 }
           98         #endif
           99 
          100         return 0;
          101 }
          102 
          103 int
          104 queue_mod_fd(int qfd, int fd, enum queue_event_type t, const void *data)
          105 {
          106         #ifdef __linux__
          107                 struct epoll_event e;
          108 
          109                 /* set event flag (only for non-shared fd's) */
          110                 e.events = EPOLLET;
          111 
          112                 switch (t) {
          113                 case QUEUE_EVENT_IN:
          114                         e.events |= EPOLLIN;
          115                         break;
          116                 case QUEUE_EVENT_OUT:
          117                         e.events |= EPOLLOUT;
          118                         break;
          119                 }
          120 
          121                 /* set data pointer */
          122                 e.data.ptr = (void *)data;
          123 
          124                 /* register fd in the interest list */
          125                 if (epoll_ctl(qfd, EPOLL_CTL_MOD, fd, &e) < 0) {
          126                         warn("epoll_ctl:");
          127                         return -1;
          128                 }
          129         #else
          130                 struct kevent e;
          131                 int events;
          132 
          133                 events = EV_CLEAR;
          134 
          135                 switch (t) {
          136                 case QUEUE_EVENT_IN:
          137                         events |= EVFILT_READ;
          138                         break;
          139                 case QUEUE_EVENT_OUT:
          140                         events |= EVFILT_WRITE;
          141                         break;
          142                 }
          143 
          144                 EV_SET(&e, fd, events, EV_ADD, 0, 0, (void *)data);
          145 
          146                 if (kevent(qfd, &e, 1, NULL, 0, NULL) < 0) {
          147                         warn("kevent:");
          148                         return -1;
          149                 }
          150         #endif
          151 
          152         return 0;
          153 }
          154 
          155 int
          156 queue_rem_fd(int qfd, int fd)
          157 {
          158         #ifdef __linux__
          159                 struct epoll_event e;
          160 
          161                 if (epoll_ctl(qfd, EPOLL_CTL_DEL, fd, &e) < 0) {
          162                         warn("epoll_ctl:");
          163                         return -1;
          164                 }
          165         #else
          166                 struct kevent e;
          167 
          168                 EV_SET(&e, fd, 0, EV_DELETE, 0, 0, 0);
          169 
          170                 if (kevent(qfd, &e, 1, NULL, 0, NULL) < 0) {
          171                         warn("kevent:");
          172                         return -1;
          173                 }
          174         #endif
          175 
          176         return 0;
          177 }
          178 
          179 ssize_t
          180 queue_wait(int qfd, queue_event *e, size_t elen)
          181 {
          182         ssize_t nready;
          183 
          184         #ifdef __linux__
          185                 if ((nready = epoll_wait(qfd, e, elen, -1)) < 0) {
          186                         warn("epoll_wait:");
          187                         return -1;
          188                 }
          189         #else
          190                 if ((nready = kevent(qfd, NULL, 0, e, elen, NULL)) < 0) {
          191                         warn("kevent:");
          192                         return -1;
          193                 }
          194         #endif
          195 
          196         return nready;
          197 }
          198 
          199 void *
          200 queue_event_get_data(const queue_event *e)
          201 {
          202         #ifdef __linux__
          203                 return e->data.ptr;
          204         #else
          205                 return e->udata;
          206         #endif
          207 }
          208 
          209 int
          210 queue_event_is_error(const queue_event *e)
          211 {
          212         #ifdef __linux__
          213                 return (e->events & ~(EPOLLIN | EPOLLOUT)) ? 1 : 0;
          214         #else
          215                 return (e->flags & EV_EOF) ? 1 : 0;
          216         #endif
          217 }