Main Page | Modules | Alphabetical List | Data Structures | Directories | File List | Data Fields | Globals | Related Pages

io_wait.h

Go to the documentation of this file.
00001 /* 
00002  * $Id: io_wait.h,v 1.29 2008/12/08 06:11:39 sobomax Exp $
00003  * 
00004  * Copyright (C) 2005 iptelorg GmbH
00005  *
00006  * Permission to use, copy, modify, and distribute this software for any
00007  * purpose with or without fee is hereby granted, provided that the above
00008  * copyright notice and this permission notice appear in all copies.
00009  *
00010  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
00011  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
00012  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
00013  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
00014  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
00015  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
00016  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
00017  */
00018 /*
00019  * tcp io wait common stuff used by tcp_main.c & tcp_read.c
00020  * All the functions are inline because of speed reasons and because they are
00021  * used only from 2 places.
00022  * You also have to define:
00023  *     int handle_io(struct fd_map* fm, short events, int idx) (see below)
00024  *     (this could be trivially replaced by a callback pointer entry attached
00025  *      to the io_wait handler if more flexibility rather then performance
00026  *      is needed)
00027  *      fd_type - define to some enum of you choice and define also
00028  *                FD_TYPE_DEFINED (if you don't do it fd_type will be defined
00029  *                to int). 0 has a special not set/not init. meaning
00030  *                (a lot of sanity checks and the sigio_rt code are based on
00031  *                 this assumption)
00032  *     local_malloc (defaults to pkg_malloc)
00033  *     local_free   (defaults to pkg_free)
00034  *  
00035  */
00036 /* 
00037  * History:
00038  * --------
00039  *  2005-06-13  created by andrei
00040  *  2005-06-26  added kqueue (andrei)
00041  *  2005-07-01  added /dev/poll (andrei)
00042  *  2006-05-30  sigio 64 bit workarround enabled for kernels < 2.6.5 (andrei)
00043  *  2007-11-22  when handle_io() is called in a loop check & stop if the fd was
00044  *               removed inside handle_io() (andrei)
00045  *  2007-11-29  support for write (POLLOUT); added io_watch_chg() (andrei)
00046  *  2008-02-04  POLLRDHUP & EPOLLRDHUP support (automatically enabled if POLLIN
00047  *               is set) (andrei)
00048  */
00049 
00050 
00051 
00052 #ifndef _io_wait_h
00053 #define _io_wait_h
00054 
00055 #include <errno.h>
00056 #include <string.h>
00057 #ifdef HAVE_SIGIO_RT
00058 #define __USE_GNU /* or else F_SETSIG won't be included */
00059 #include <sys/types.h> /* recv */
00060 #include <sys/socket.h> /* recv */
00061 #include <signal.h> /* sigprocmask, sigwait a.s.o */
00062 #endif
00063 
00064 #define _GNU_SOURCE  /* for POLLRDHUP on linux */
00065 #include <sys/poll.h>
00066 #include <fcntl.h>
00067 
00068 #ifdef HAVE_EPOLL
00069 #include <sys/epoll.h>
00070 #endif
00071 #ifdef HAVE_KQUEUE
00072 #include <sys/types.h> /* needed on freebsd */
00073 #include <sys/event.h>
00074 #include <sys/time.h>
00075 #endif
00076 #ifdef HAVE_DEVPOLL
00077 #include <sys/devpoll.h>
00078 #endif
00079 #ifdef HAVE_SELECT
00080 /* needed on openbsd for select*/
00081 #include <sys/time.h> 
00082 #include <sys/types.h> 
00083 #include <unistd.h>
00084 /* needed according to POSIX for select*/
00085 #include <sys/select.h>
00086 #endif
00087 
00088 #include "dprint.h"
00089 
00090 #include "poll_types.h" /* poll_types*/
00091 #ifdef HAVE_SIGIO_RT
00092 #include "pt.h" /* mypid() */
00093 #endif
00094 
00095 #include "compiler_opt.h"
00096 
00097 
00098 #ifdef HAVE_EPOLL
00099 /* fix defines for EPOLL */
00100 #if defined POLLRDHUP && ! defined EPOLLRDHUP
00101 #define EPOLLRDHUP POLLRDHUP  /* should work on all linuxes */
00102 #endif /* POLLRDHUP && EPOLLRDHUP */
00103 #endif /* HAVE_EPOLL */
00104 
00105 
00106 extern int _os_ver; /* os version number, needed to select bugs workarrounds */
00107 
00108 
00109 #if 0
00110 enum fd_types; /* this should be defined from the including file,
00111                                   see tcp_main.c for an example, 
00112                                   0 has a special meaning: not used/empty*/
00113 #endif
00114 
00115 #ifndef FD_TYPE_DEFINED
00116 typedef int fd_type;
00117 #define FD_TYPE_DEFINED
00118 #endif
00119 
00120 /* maps a fd to some other structure; used in almost all cases
00121  * except epoll and maybe kqueue or /dev/poll */
00122 struct fd_map{
00123         int fd;               /* fd no */
00124         fd_type type;         /* "data" type */
00125         void* data;           /* pointer to the corresponding structure */
00126         short events;         /* events we are interested int */
00127 };
00128 
00129 
00130 #ifdef HAVE_KQUEUE
00131 #ifndef KQ_CHANGES_ARRAY_SIZE
00132 #define KQ_CHANGES_ARRAY_SIZE 256
00133 
00134 #ifdef __OS_netbsd
00135 #define KEV_UDATA_CAST (intptr_t)
00136 #else
00137 #define KEV_UDATA_CAST
00138 #endif
00139 
00140 #endif
00141 #endif
00142 
00143 
00144 /* handler structure */
00145 struct io_wait_handler{
00146         enum poll_types poll_method;
00147         int flags;
00148         struct fd_map* fd_hash;
00149         int fd_no; /*  current index used in fd_array and the passed size for 
00150                                    ep_array & kq_array*/
00151         int max_fd_no; /* maximum fd no, is also the size of fd_array,
00152                                                        fd_hash  and ep_array*/
00153         /* common stuff for POLL, SIGIO_RT and SELECT
00154          * since poll support is always compiled => this will always be compiled */
00155         struct pollfd* fd_array; /* used also by devpoll as devpoll array */
00156         int crt_fd_array_idx; /*  crt idx for which handle_io is called
00157                                                          (updated also by del -> internal optimization) */
00158         /* end of common stuff */
00159 #ifdef HAVE_EPOLL
00160         int epfd; /* epoll ctrl fd */
00161         struct epoll_event* ep_array;
00162 #endif
00163 #ifdef HAVE_SIGIO_RT
00164         sigset_t sset; /* signal mask for sigio & sigrtmin */
00165         int signo;     /* real time signal used */
00166 #endif
00167 #ifdef HAVE_KQUEUE
00168         int kq_fd;
00169         struct kevent* kq_array;   /* used for the eventlist*/
00170         struct kevent* kq_changes; /* used for the changelist */
00171         size_t kq_nchanges;
00172         size_t kq_changes_size; /* size of the changes array */
00173 #endif
00174 #ifdef HAVE_DEVPOLL
00175         int dpoll_fd;
00176 #endif
00177 #ifdef HAVE_SELECT
00178         fd_set master_rset; /* read set */
00179         fd_set master_wset; /* write set */
00180         int max_fd_select; /* maximum select used fd */
00181 #endif
00182 };
00183 
00184 typedef struct io_wait_handler io_wait_h;
00185 
00186 
00187 /* get the corresponding fd_map structure pointer */
00188 #define get_fd_map(h, fd)               (&(h)->fd_hash[(fd)])
00189 /* remove a fd_map structure from the hash; the pointer must be returned
00190  * by get_fd_map or hash_fd_map*/
00191 #define unhash_fd_map(pfm)      \
00192         do{ \
00193                 (pfm)->type=0 /*F_NONE */; \
00194                 (pfm)->fd=-1; \
00195         }while(0)
00196 
00197 /* add a fd_map structure to the fd hash */
00198 static inline struct fd_map* hash_fd_map(       io_wait_h* h,
00199                                                                                         int fd,
00200                                                                                         short events,
00201                                                                                         fd_type type,
00202                                                                                         void* data)
00203 {
00204         h->fd_hash[fd].fd=fd;
00205         h->fd_hash[fd].events=events;
00206         h->fd_hash[fd].type=type;
00207         h->fd_hash[fd].data=data;
00208         return &h->fd_hash[fd];
00209 }
00210 
00211 
00212 
00213 #ifdef HANDLE_IO_INLINE
00214 /* generic handle io routine, this must be defined in the including file
00215  * (faster then registering a callback pointer)
00216  *
00217  * params:  fm     - pointer to a fd hash entry
00218  *          events - combinations of POLLIN, POLLOUT, POLLERR & POLLHUP
00219  *          idx    - index in the fd_array (or -1 if not known)
00220  * return: -1 on error
00221  *          0 on EAGAIN or when by some other way it is known that no more 
00222  *            io events are queued on the fd (the receive buffer is empty).
00223  *            Usefull to detect when there are no more io events queued for
00224  *            sigio_rt, epoll_et, kqueue.
00225  *         >0 on successfull read from the fd (when there might be more io
00226  *            queued -- the receive buffer might still be non-empty)
00227  */
00228 inline static int handle_io(struct fd_map* fm, short events, int idx);
00229 #else
00230 int handle_io(struct fd_map* fm, short events, int idx);
00231 #endif
00232 
00233 
00234 
00235 #ifdef HAVE_KQUEUE
00236 /*
00237  * kqueue specific function: register a change
00238  * (adds a change to the kevent change array, and if full flushes it first)
00239  *
00240  * TODO: check if the event already exists in the change list or if it's
00241  *       complementary to an event in the list (e.g. EVFILT_WRITE, EV_DELETE
00242  *       and EVFILT_WRITE, EV_ADD for the same fd).
00243  * returns: -1 on error, 0 on success
00244  */
00245 static inline int kq_ev_change(io_wait_h* h, int fd, int filter, int flag, 
00246                                                                 void* data)
00247 {
00248         int n;
00249         struct timespec tspec;
00250 
00251         if (h->kq_nchanges>=h->kq_changes_size){
00252                 /* changes array full ! */
00253                 LOG(L_WARN, "WARNING: kq_ev_change: kqueue changes array full"
00254                                         " trying to flush...\n");
00255                 tspec.tv_sec=0;
00256                 tspec.tv_nsec=0;
00257 again:
00258                 n=kevent(h->kq_fd, h->kq_changes, h->kq_nchanges, 0, 0, &tspec);
00259                 if (n==-1){
00260                         if (errno==EINTR) goto again;
00261                         LOG(L_ERR, "ERROR: io_watch_add: kevent flush changes "
00262                                                 " failed: %s [%d]\n", strerror(errno), errno);
00263                         return -1;
00264                 }
00265                 h->kq_nchanges=0; /* changes array is empty */
00266         }
00267         EV_SET(&h->kq_changes[h->kq_nchanges], fd, filter, flag, 0, 0,
00268                         KEV_UDATA_CAST data);
00269         h->kq_nchanges++;
00270         return 0;
00271 }
00272 #endif
00273 
00274 
00275 
00276 /* generic io_watch_add function
00277  * Params:
00278  *     h      - pointer to initialized io_wait handle
00279  *     fd     - fd to watch
00280  *     events - bitmap with the fd events for which the fd should be watched
00281  *              (combination of POLLIN and POLLOUT)
00282  *     type   - fd type (non 0 value, returned in the call to handle_io)
00283  *     data   - pointer/private data returned in the handle_io call
00284  * returns 0 on success, -1 on error
00285  *
00286  * WARNING: handle_io() can be called immediately (from io_watch_add()) so
00287  *  make sure that any dependent init. (e.g. data stuff) is made before
00288  *  calling io_watch_add
00289  *
00290  * this version should be faster than pointers to poll_method specific
00291  * functions (it avoids functions calls, the overhead being only an extra
00292  *  switch())*/
00293 inline static int io_watch_add( io_wait_h* h,
00294                                                                 int fd,
00295                                                                 short events,
00296                                                                 fd_type type,
00297                                                                 void* data)
00298 {
00299 
00300         /* helper macros */
00301 #define fd_array_setup(ev) \
00302         do{ \
00303                 h->fd_array[h->fd_no].fd=fd; \
00304                 h->fd_array[h->fd_no].events=(ev); /* useless for select */ \
00305                 h->fd_array[h->fd_no].revents=0;     /* useless for select */ \
00306         }while(0)
00307         
00308 #define set_fd_flags(f) \
00309         do{ \
00310                         flags=fcntl(fd, F_GETFL); \
00311                         if (flags==-1){ \
00312                                 LOG(L_ERR, "ERROR: io_watch_add: fnctl: GETFL failed:" \
00313                                                 " %s [%d]\n", strerror(errno), errno); \
00314                                 goto error; \
00315                         } \
00316                         if (fcntl(fd, F_SETFL, flags|(f))==-1){ \
00317                                 LOG(L_ERR, "ERROR: io_watch_add: fnctl: SETFL" \
00318                                                         " failed: %s [%d]\n", strerror(errno), errno); \
00319                                 goto error; \
00320                         } \
00321         }while(0)
00322         
00323         
00324         struct fd_map* e;
00325         int flags;
00326 #ifdef HAVE_EPOLL
00327         struct epoll_event ep_event;
00328 #endif
00329 #ifdef HAVE_DEVPOLL
00330         struct pollfd pfd;
00331 #endif
00332 #if defined(HAVE_SIGIO_RT) || defined (HAVE_EPOLL)
00333         int n;
00334 #endif
00335 #if defined(HAVE_SIGIO_RT)
00336         int idx;
00337         int check_io;
00338         struct pollfd pf;
00339         
00340         check_io=0; /* set to 1 if we need to check for pre-existing queued
00341                                    io/data on the fd */
00342         idx=-1;
00343 #endif
00344         e=0;
00345         /* sanity checks */
00346         if (unlikely(fd==-1)){
00347                 LOG(L_CRIT, "BUG: io_watch_add: fd is -1!\n");
00348                 goto error;
00349         }
00350         if (unlikely((events&(POLLIN|POLLOUT))==0)){
00351                 LOG(L_CRIT, "BUG: io_watch_add: invalid events: 0x%0x\n", events);
00352                 goto error;
00353         }
00354         /* check if not too big */
00355         if (unlikely(h->fd_no>=h->max_fd_no)){
00356                 LOG(L_CRIT, "ERROR: io_watch_add: maximum fd number exceeded:"
00357                                 " %d/%d\n", h->fd_no, h->max_fd_no);
00358                 goto error;
00359         }
00360         DBG("DBG: io_watch_add(%p, %d, %d, %p), fd_no=%d\n",
00361                         h, fd, type, data, h->fd_no);
00362         /*  hash sanity check */
00363         e=get_fd_map(h, fd);
00364         if (unlikely(e && (e->type!=0 /*F_NONE*/))){
00365                 LOG(L_ERR, "ERROR: io_watch_add: trying to overwrite entry %d"
00366                                 " watched for %x in the hash(%d, %d, %p) with (%d, %d, %p)\n",
00367                                 fd, events, e->fd, e->type, e->data, fd, type, data);
00368                 e=0;
00369                 goto error;
00370         }
00371         
00372         if (unlikely((e=hash_fd_map(h, fd, events, type, data))==0)){
00373                 LOG(L_ERR, "ERROR: io_watch_add: failed to hash the fd %d\n", fd);
00374                 goto error;
00375         }
00376         switch(h->poll_method){ /* faster then pointer to functions */
00377                 case POLL_POLL:
00378 #ifdef POLLRDHUP
00379                         /* listen to POLLRDHUP by default (if POLLIN) */
00380                         events|=((int)!(events & POLLIN) - 1) & POLLRDHUP;
00381 #endif /* POLLRDHUP */
00382                         fd_array_setup(events);
00383                         set_fd_flags(O_NONBLOCK);
00384                         break;
00385 #ifdef HAVE_SELECT
00386                 case POLL_SELECT:
00387                         fd_array_setup(events);
00388                         if (likely(events & POLLIN))
00389                                 FD_SET(fd, &h->master_rset);
00390                         if (unlikely(events & POLLOUT))
00391                                 FD_SET(fd, &h->master_wset);
00392                         if (h->max_fd_select<fd) h->max_fd_select=fd;
00393                         break;
00394 #endif
00395 #ifdef HAVE_SIGIO_RT
00396                 case POLL_SIGIO_RT:
00397                         fd_array_setup(events);
00398                         /* re-set O_ASYNC might be needed, if not done from 
00399                          * io_watch_del (or if somebody wants to add a fd which has
00400                          * already O_ASYNC/F_SETSIG set on a duplicate)
00401                          */
00402                         /* set async & signal */
00403                         if (fcntl(fd, F_SETOWN, my_pid())==-1){
00404                                 LOG(L_ERR, "ERROR: io_watch_add: fnctl: SETOWN"
00405                                 " failed: %s [%d]\n", strerror(errno), errno);
00406                                 goto error;
00407                         }
00408                         if (fcntl(fd, F_SETSIG, h->signo)==-1){
00409                                 LOG(L_ERR, "ERROR: io_watch_add: fnctl: SETSIG"
00410                                         " failed: %s [%d]\n", strerror(errno), errno);
00411                                 goto error;
00412                         }
00413                         /* set both non-blocking and async */
00414                         set_fd_flags(O_ASYNC| O_NONBLOCK);
00415 #ifdef EXTRA_DEBUG
00416                         DBG("io_watch_add: sigio_rt on f %d, signal %d to pid %d\n",
00417                                         fd,  h->signo, my_pid());
00418 #endif
00419                         /* empty socket receive buffer, if buffer is already full
00420                          * no more space to put packets
00421                          * => no more signals are ever generated
00422                          * also when moving fds, the freshly moved fd might have
00423                          *  already some bytes queued, we want to get them now
00424                          *  and not later -- andrei */
00425                         idx=h->fd_no;
00426                         check_io=1;
00427                         break;
00428 #endif
00429 #ifdef HAVE_EPOLL
00430                 case POLL_EPOLL_LT:
00431                         ep_event.events=
00432 #ifdef POLLRDHUP
00433                                                 /* listen for EPOLLRDHUP too */
00434                                                 ((EPOLLIN|EPOLLRDHUP) & ((int)!(events & POLLIN)-1) ) |
00435 #else /* POLLRDHUP */
00436                                                 (EPOLLIN & ((int)!(events & POLLIN)-1) ) |
00437 #endif /* POLLRDHUP */
00438                                                 (EPOLLOUT & ((int)!(events & POLLOUT)-1) );
00439                         ep_event.data.ptr=e;
00440 again1:
00441                         n=epoll_ctl(h->epfd, EPOLL_CTL_ADD, fd, &ep_event);
00442                         if (unlikely(n==-1)){
00443                                 if (errno==EAGAIN) goto again1;
00444                                 LOG(L_ERR, "ERROR: io_watch_add: epoll_ctl failed: %s [%d]\n",
00445                                         strerror(errno), errno);
00446                                 goto error;
00447                         }
00448                         break;
00449                 case POLL_EPOLL_ET:
00450                         set_fd_flags(O_NONBLOCK);
00451                         ep_event.events=
00452 #ifdef POLLRDHUP
00453                                                 /* listen for EPOLLRDHUP too */
00454                                                 ((EPOLLIN|EPOLLRDHUP) & ((int)!(events & POLLIN)-1) ) |
00455 #else /* POLLRDHUP */
00456                                                 (EPOLLIN & ((int)!(events & POLLIN)-1) ) |
00457 #endif /* POLLRDHUP */
00458                                                 (EPOLLOUT & ((int)!(events & POLLOUT)-1) ) |
00459                                                 EPOLLET;
00460                         ep_event.data.ptr=e;
00461 again2:
00462                         n=epoll_ctl(h->epfd, EPOLL_CTL_ADD, fd, &ep_event);
00463                         if (unlikely(n==-1)){
00464                                 if (errno==EAGAIN) goto again2;
00465                                 LOG(L_ERR, "ERROR: io_watch_add: epoll_ctl failed: %s [%d]\n",
00466                                         strerror(errno), errno);
00467                                 goto error;
00468                         }
00469                         break;
00470 #endif
00471 #ifdef HAVE_KQUEUE
00472                 case POLL_KQUEUE:
00473                         if (likely( events & POLLIN)){
00474                                 if (unlikely(kq_ev_change(h, fd, EVFILT_READ, EV_ADD, e)==-1))
00475                                 goto error;
00476                         }
00477                         if (unlikely( events & POLLOUT)){
00478                                 if (unlikely(kq_ev_change(h, fd, EVFILT_WRITE, EV_ADD, e)==-1))
00479                                 {
00480                                         if (likely(events & POLLIN)){
00481                                                 kq_ev_change(h, fd, EVFILT_READ, EV_DELETE, 0);
00482                                         }
00483                                 }
00484                                 goto error;
00485                         }
00486                         break;
00487 #endif
00488 #ifdef HAVE_DEVPOLL
00489                 case POLL_DEVPOLL:
00490                         pfd.fd=fd;
00491                         pfd.events=events;
00492                         pfd.revents=0;
00493 again_devpoll:
00494                         if (write(h->dpoll_fd, &pfd, sizeof(pfd))==-1){
00495                                 if (errno==EAGAIN) goto again_devpoll;
00496                                 LOG(L_ERR, "ERROR: io_watch_add: /dev/poll write failed:"
00497                                                         "%s [%d]\n", strerror(errno), errno);
00498                                 goto error;
00499                         }
00500                         break;
00501 #endif
00502                         
00503                 default:
00504                         LOG(L_CRIT, "BUG: io_watch_add: no support for poll method "
00505                                         " %s (%d)\n", poll_method_str[h->poll_method],
00506                                         h->poll_method);
00507                         goto error;
00508         }
00509         
00510         h->fd_no++; /* "activate" changes, for epoll/kqueue/devpoll it
00511                                    has only informative value */
00512 #if defined(HAVE_SIGIO_RT)
00513         if (check_io){
00514                 /* handle possible pre-existing events */
00515                 pf.fd=fd;
00516                 pf.events=events;
00517 check_io_again:
00518                 n=0;
00519                 while(e->type && ((n=poll(&pf, 1, 0))>0) && 
00520                                 (handle_io(e, pf.revents, idx)>0) &&
00521                                 (pf.revents & (e->events|POLLERR|POLLHUP)));
00522                 if (unlikely(e->type && (n==-1))){
00523                         if (errno==EINTR) goto check_io_again;
00524                         LOG(L_ERR, "ERROR: io_watch_add: check_io poll: %s [%d]\n",
00525                                                 strerror(errno), errno);
00526                 }
00527         }
00528 #endif
00529         return 0;
00530 error:
00531         if (e) unhash_fd_map(e);
00532         return -1;
00533 #undef fd_array_setup
00534 #undef set_fd_flags 
00535 }
00536 
00537 
00538 
00539 #define IO_FD_CLOSING 16
00540 /* parameters:    h - handler 
00541  *               fd - file descriptor
00542  *            index - index in the fd_array if known, -1 if not
00543  *                    (if index==-1 fd_array will be searched for the
00544  *                     corresponding fd* entry -- slower but unavoidable in 
00545  *                     some cases). index is not used (no fd_array) for epoll,
00546  *                     /dev/poll and kqueue
00547  *            flags - optimization flags, e.g. IO_FD_CLOSING, the fd was 
00548  *                    or will shortly be closed, in some cases we can avoid
00549  *                    extra remove operations (e.g.: epoll, kqueue, sigio)
00550  * returns 0 if ok, -1 on error */
00551 inline static int io_watch_del(io_wait_h* h, int fd, int idx, int flags)
00552 {
00553         
00554 #define fix_fd_array \
00555         do{\
00556                         if (unlikely(idx==-1)){ \
00557                                 /* fix idx if -1 and needed */ \
00558                                 for (idx=0; (idx<h->fd_no) && \
00559                                                         (h->fd_array[idx].fd!=fd); idx++); \
00560                         } \
00561                         if (likely(idx<h->fd_no)){ \
00562                                 memmove(&h->fd_array[idx], &h->fd_array[idx+1], \
00563                                         (h->fd_no-(idx+1))*sizeof(*(h->fd_array))); \
00564                                 if ((idx<=h->crt_fd_array_idx) && (h->crt_fd_array_idx>=0)) \
00565                                         h->crt_fd_array_idx--; \
00566                         } \
00567         }while(0)
00568         
00569         struct fd_map* e;
00570         int events;
00571 #ifdef HAVE_EPOLL
00572         int n;
00573         struct epoll_event ep_event;
00574 #endif
00575 #ifdef HAVE_DEVPOLL
00576         struct pollfd pfd;
00577 #endif
00578 #ifdef HAVE_SIGIO_RT
00579         int fd_flags;
00580 #endif
00581         
00582         if (unlikely((fd<0) || (fd>=h->max_fd_no))){
00583                 LOG(L_CRIT, "BUG: io_watch_del: invalid fd %d, not in [0, %d) \n",
00584                                                 fd, h->fd_no);
00585                 goto error;
00586         }
00587         DBG("DBG: io_watch_del (%p, %d, %d, 0x%x) fd_no=%d called\n",
00588                         h, fd, idx, flags, h->fd_no);
00589         e=get_fd_map(h, fd);
00590         /* more sanity checks */
00591         if (unlikely(e==0)){
00592                 LOG(L_CRIT, "BUG: io_watch_del: no corresponding hash entry for %d\n",
00593                                         fd);
00594                 goto error;
00595         }
00596         if (unlikely(e->type==0 /*F_NONE*/)){
00597                 LOG(L_ERR, "ERROR: io_watch_del: trying to delete already erased"
00598                                 " entry %d in the hash(%d, %d, %p) flags %x)\n",
00599                                 fd, e->fd, e->type, e->data, flags);
00600                 goto error;
00601         }
00602         events=e->events;
00603         unhash_fd_map(e);
00604         
00605         switch(h->poll_method){
00606                 case POLL_POLL:
00607                         fix_fd_array;
00608                         break;
00609 #ifdef HAVE_SELECT
00610                 case POLL_SELECT:
00611                         if (likely(events & POLLIN))
00612                                 FD_CLR(fd, &h->master_rset);
00613                         if (unlikely(events & POLLOUT))
00614                                 FD_CLR(fd, &h->master_wset);
00615                         if (unlikely(h->max_fd_select && (h->max_fd_select==fd)))
00616                                 /* we don't know the prev. max, so we just decrement it */
00617                                 h->max_fd_select--; 
00618                         fix_fd_array;
00619                         break;
00620 #endif
00621 #ifdef HAVE_SIGIO_RT
00622                 case POLL_SIGIO_RT:
00623                         fix_fd_array;
00624                         /* the O_ASYNC flag must be reset all the time, the fd
00625                          *  can be changed only if  O_ASYNC is reset (if not and
00626                          *  the fd is a duplicate, you will get signals from the dup. fd
00627                          *  and not from the original, even if the dup. fd was closed
00628                          *  and the signals re-set on the original) -- andrei
00629                          */
00630                         /*if (!(flags & IO_FD_CLOSING)){*/
00631                                 /* reset ASYNC */
00632                                 fd_flags=fcntl(fd, F_GETFL); 
00633                                 if (unlikely(fd_flags==-1)){ 
00634                                         LOG(L_ERR, "ERROR: io_watch_del: fnctl: GETFL failed:" 
00635                                                         " %s [%d]\n", strerror(errno), errno); 
00636                                         goto error; 
00637                                 } 
00638                                 if (unlikely(fcntl(fd, F_SETFL, fd_flags&(~O_ASYNC))==-1)){ 
00639                                         LOG(L_ERR, "ERROR: io_watch_del: fnctl: SETFL" 
00640                                                                 " failed: %s [%d]\n", strerror(errno), errno); 
00641                                         goto error; 
00642                                 } 
00643                         break;
00644 #endif
00645 #ifdef HAVE_EPOLL
00646                 case POLL_EPOLL_LT:
00647                 case POLL_EPOLL_ET:
00648                         /* epoll doesn't seem to automatically remove sockets,
00649                          * if the socket is a duplicate/moved and the original
00650                          * is still open. The fd is removed from the epoll set
00651                          * only when the original (and all the  copies?) is/are 
00652                          * closed. This is probably a bug in epoll. --andrei */
00653 #ifdef EPOLL_NO_CLOSE_BUG
00654                         if (!(flags & IO_FD_CLOSING)){
00655 #endif
00656 again_epoll:
00657                                 n=epoll_ctl(h->epfd, EPOLL_CTL_DEL, fd, &ep_event);
00658                                 if (unlikely(n==-1)){
00659                                         if (errno==EAGAIN) goto again_epoll;
00660                                         LOG(L_ERR, "ERROR: io_watch_del: removing fd from epoll "
00661                                                         "list failed: %s [%d]\n", strerror(errno), errno);
00662                                         goto error;
00663                                 }
00664 #ifdef EPOLL_NO_CLOSE_BUG
00665                         }
00666 #endif
00667                         break;
00668 #endif
00669 #ifdef HAVE_KQUEUE
00670                 case POLL_KQUEUE:
00671                         if (!(flags & IO_FD_CLOSING)){
00672                                 if (likely(events & POLLIN)){
00673                                         if (unlikely(kq_ev_change(h, fd, EVFILT_READ,
00674                                                                                                         EV_DELETE, 0) ==-1)){
00675                                                 /* try to delete the write filter anyway */
00676                                                 if (events & POLLOUT){
00677                                                         kq_ev_change(h, fd, EVFILT_WRITE, EV_DELETE, 0);
00678                                                 }
00679                                                 goto error;
00680                                         }
00681                                 }
00682                                 if (unlikely(events & POLLOUT)){
00683                                         if (unlikely(kq_ev_change(h, fd, EVFILT_WRITE,
00684                                                                                                         EV_DELETE, 0) ==-1))
00685                                                 goto error;
00686                                 }
00687                         }
00688                         break;
00689 #endif
00690 #ifdef HAVE_DEVPOLL
00691                 case POLL_DEVPOLL:
00692                                 /* for /dev/poll the closed fds _must_ be removed
00693                                    (they are not removed automatically on close()) */
00694                                 pfd.fd=fd;
00695                                 pfd.events=POLLREMOVE;
00696                                 pfd.revents=0;
00697 again_devpoll:
00698                                 if (write(h->dpoll_fd, &pfd, sizeof(pfd))==-1){
00699                                         if (errno==EINTR) goto again_devpoll;
00700                                         LOG(L_ERR, "ERROR: io_watch_del: removing fd from "
00701                                                                 "/dev/poll failed: %s [%d]\n", 
00702                                                                 strerror(errno), errno);
00703                                         goto error;
00704                                 }
00705                                 break;
00706 #endif
00707                 default:
00708                         LOG(L_CRIT, "BUG: io_watch_del: no support for poll method "
00709                                         " %s (%d)\n", poll_method_str[h->poll_method], 
00710                                         h->poll_method);
00711                         goto error;
00712         }
00713         h->fd_no--;
00714         return 0;
00715 error:
00716         return -1;
00717 #undef fix_fd_array
00718 }
00719 
00720 
00721 
00722 /* parameters:    h - handler 
00723  *               fd - file descriptor
00724  *           events - new events to watch for
00725  *              idx - index in the fd_array if known, -1 if not
00726  *                    (if index==-1 fd_array will be searched for the
00727  *                     corresponding fd* entry -- slower but unavoidable in 
00728  *                     some cases). index is not used (no fd_array) for epoll,
00729  *                     /dev/poll and kqueue
00730  * returns 0 if ok, -1 on error */
00731 inline static int io_watch_chg(io_wait_h* h, int fd, short events, int idx )
00732 {
00733         
00734 #define fd_array_chg(ev) \
00735         do{\
00736                         if (unlikely(idx==-1)){ \
00737                                 /* fix idx if -1 and needed */ \
00738                                 for (idx=0; (idx<h->fd_no) && \
00739                                                         (h->fd_array[idx].fd!=fd); idx++); \
00740                         } \
00741                         if (likely(idx<h->fd_no)){ \
00742                                 h->fd_array[idx].events=(ev); \
00743                         } \
00744         }while(0)
00745         
00746         struct fd_map* e;
00747         int add_events;
00748         int del_events;
00749 #ifdef HAVE_DEVPOLL
00750         struct pollfd pfd;
00751 #endif
00752 #ifdef HAVE_EPOLL
00753         int n;
00754         struct epoll_event ep_event;
00755 #endif
00756         
00757         if (unlikely((fd<0) || (fd>=h->max_fd_no))){
00758                 LOG(L_CRIT, "BUG: io_watch_chg: invalid fd %d, not in [0, %d) \n",
00759                                                 fd, h->fd_no);
00760                 goto error;
00761         }
00762         if (unlikely((events&(POLLIN|POLLOUT))==0)){
00763                 LOG(L_CRIT, "BUG: io_watch_chg: invalid events: 0x%0x\n", events);
00764                 goto error;
00765         }
00766         DBG("DBG: io_watch_chg (%p, %d, 0x%x, 0x%x) fd_no=%d called\n",
00767                         h, fd, events, idx, h->fd_no);
00768         e=get_fd_map(h, fd);
00769         /* more sanity checks */
00770         if (unlikely(e==0)){
00771                 LOG(L_CRIT, "BUG: io_watch_chg: no corresponding hash entry for %d\n",
00772                                         fd);
00773                 goto error;
00774         }
00775         if (unlikely(e->type==0 /*F_NONE*/)){
00776                 LOG(L_ERR, "ERROR: io_watch_chg: trying to change an already erased"
00777                                 " entry %d in the hash(%d, %d, %p) )\n",
00778                                 fd, e->fd, e->type, e->data);
00779                 goto error;
00780         }
00781         
00782         add_events=events & ~e->events;
00783         del_events=e->events & ~events;
00784         e->events=events;
00785         switch(h->poll_method){
00786                 case POLL_POLL:
00787 #ifdef POLLRDHUP
00788                         /* listen to POLLRDHUP by default (if POLLIN) */
00789                         events|=((int)!(events & POLLIN) - 1) & POLLRDHUP;
00790 #endif /* POLLRDHUP */
00791                         fd_array_chg(events);
00792                         break;
00793 #ifdef HAVE_SELECT
00794                 case POLL_SELECT:
00795                         fd_array_chg(events);
00796                         if (unlikely(del_events & POLLIN))
00797                                 FD_CLR(fd, &h->master_rset);
00798                         else if (unlikely(add_events & POLLIN))
00799                                 FD_SET(fd, &h->master_rset);
00800                         if (likely(del_events & POLLOUT))
00801                                 FD_CLR(fd, &h->master_wset);
00802                         else if (likely(add_events & POLLOUT))
00803                                 FD_SET(fd, &h->master_wset);
00804                         break;
00805 #endif
00806 #ifdef HAVE_SIGIO_RT
00807                 case POLL_SIGIO_RT:
00808                         fd_array_chg(events);
00809                         /* no need for check_io, since SIGIO_RT listens by default for all
00810                          * the events */
00811                         break;
00812 #endif
00813 #ifdef HAVE_EPOLL
00814                 case POLL_EPOLL_LT:
00815                                 ep_event.events=
00816 #ifdef POLLRDHUP
00817                                                 /* listen for EPOLLRDHUP too */
00818                                                 ((EPOLLIN|EPOLLRDHUP) & ((int)!(events & POLLIN)-1) ) |
00819 #else /* POLLRDHUP */
00820                                                 (EPOLLIN & ((int)!(events & POLLIN)-1) ) |
00821 #endif /* POLLRDHUP */
00822                                                 (EPOLLOUT & ((int)!(events & POLLOUT)-1) );
00823                                 ep_event.data.ptr=e;
00824 again_epoll_lt:
00825                                 n=epoll_ctl(h->epfd, EPOLL_CTL_MOD, fd, &ep_event);
00826                                 if (unlikely(n==-1)){
00827                                         if (errno==EAGAIN) goto again_epoll_lt;
00828                                         LOG(L_ERR, "ERROR: io_watch_chg: modifying epoll events"
00829                                                         " failed: %s [%d]\n", strerror(errno), errno);
00830                                         goto error;
00831                                 }
00832                         break;
00833                 case POLL_EPOLL_ET:
00834                                 ep_event.events=
00835 #ifdef POLLRDHUP
00836                                                 /* listen for EPOLLRDHUP too */
00837                                                 ((EPOLLIN|EPOLLRDHUP) & ((int)!(events & POLLIN)-1) ) |
00838 #else /* POLLRDHUP */
00839                                                 (EPOLLIN & ((int)!(events & POLLIN)-1) ) |
00840 #endif /* POLLRDHUP */
00841                                                 (EPOLLOUT & ((int)!(events & POLLOUT)-1) ) |
00842                                                 EPOLLET;
00843                                 ep_event.data.ptr=e;
00844 again_epoll_et:
00845                                 n=epoll_ctl(h->epfd, EPOLL_CTL_MOD, fd, &ep_event);
00846                                 if (unlikely(n==-1)){
00847                                         if (errno==EAGAIN) goto again_epoll_et;
00848                                         LOG(L_ERR, "ERROR: io_watch_chg: modifying epoll events"
00849                                                         " failed: %s [%d]\n", strerror(errno), errno);
00850                                         goto error;
00851                                 }
00852                         break;
00853 #endif
00854 #ifdef HAVE_KQUEUE
00855                 case POLL_KQUEUE:
00856                         if (unlikely(del_events & POLLIN)){
00857                                 if (unlikely(kq_ev_change(h, fd, EVFILT_READ,
00858                                                                                                                 EV_DELETE, 0) ==-1))
00859                                                 goto error;
00860                         }else if (unlikely(add_events & POLLIN)){
00861                                 if (unlikely(kq_ev_change(h, fd, EVFILT_READ, EV_ADD, e) ==-1))
00862                                         goto error;
00863                         }
00864                         if (likely(del_events & POLLOUT)){
00865                                 if (unlikely(kq_ev_change(h, fd, EVFILT_WRITE,
00866                                                                                                                 EV_DELETE, 0) ==-1))
00867                                                 goto error;
00868                         }else if (likely(add_events & POLLOUT)){
00869                                 if (unlikely(kq_ev_change(h, fd, EVFILT_WRITE, EV_ADD, e)==-1))
00870                                         goto error;
00871                         }
00872                         break;
00873 #endif
00874 #ifdef HAVE_DEVPOLL
00875                 case POLL_DEVPOLL:
00876                                 /* for /dev/poll the closed fds _must_ be removed
00877                                    (they are not removed automatically on close()) */
00878                                 pfd.fd=fd;
00879                                 pfd.events=POLLREMOVE;
00880                                 pfd.revents=0;
00881 again_devpoll1:
00882                                 if (unlikely(write(h->dpoll_fd, &pfd, sizeof(pfd))==-1)){
00883                                         if (errno==EINTR) goto again_devpoll1;
00884                                         LOG(L_ERR, "ERROR: io_watch_chg: removing fd from "
00885                                                                 "/dev/poll failed: %s [%d]\n", 
00886                                                                 strerror(errno), errno);
00887                                         goto error;
00888                                 }
00889 again_devpoll2:
00890                                 pfd.events=events;
00891                                 pfd.revents=0;
00892                                 if (unlikely(write(h->dpoll_fd, &pfd, sizeof(pfd))==-1)){
00893                                         if (errno==EINTR) goto again_devpoll2;
00894                                         LOG(L_ERR, "ERROR: io_watch_chg: re-adding fd to "
00895                                                                 "/dev/poll failed: %s [%d]\n", 
00896                                                                 strerror(errno), errno);
00897                                         goto error;
00898                                 }
00899                                 break;
00900 #endif
00901                 default:
00902                         LOG(L_CRIT, "BUG: io_watch_chg: no support for poll method "
00903                                         " %s (%d)\n", poll_method_str[h->poll_method], 
00904                                         h->poll_method);
00905                         goto error;
00906         }
00907         return 0;
00908 error:
00909         return -1;
00910 #undef fix_fd_array
00911 }
00912 
00913 
00914 
00915 /* io_wait_loop_x style function 
00916  * wait for io using poll()
00917  * params: h      - io_wait handle
00918  *         t      - timeout in s
00919  *         repeat - if !=0 handle_io will be called until it returns <=0
00920  * returns: number of IO events handled on success (can be 0), -1 on error
00921  */
00922 inline static int io_wait_loop_poll(io_wait_h* h, int t, int repeat)
00923 {
00924         int n, r;
00925         int ret;
00926         struct fd_map* fm;
00927         
00928 again:
00929                 ret=n=poll(h->fd_array, h->fd_no, t*1000);
00930                 if (n==-1){
00931                         if (errno==EINTR) goto again; /* signal, ignore it */
00932                         else{
00933                                 LOG(L_ERR, "ERROR:io_wait_loop_poll: poll: %s [%d]\n",
00934                                                 strerror(errno), errno);
00935                                 goto error;
00936                         }
00937                 }
00938                 for (r=0; (r<h->fd_no) && n; r++){
00939                         fm=get_fd_map(h, h->fd_array[r].fd);
00940                         if (h->fd_array[r].revents & (fm->events|POLLERR|POLLHUP)){
00941                                 n--;
00942                                 /* sanity checks */
00943                                 if (unlikely((h->fd_array[r].fd >= h->max_fd_no)||
00944                                                                 (h->fd_array[r].fd < 0))){
00945                                         LOG(L_CRIT, "BUG: io_wait_loop_poll: bad fd %d "
00946                                                         "(no in the 0 - %d range)\n",
00947                                                         h->fd_array[r].fd, h->max_fd_no);
00948                                         /* try to continue anyway */
00949                                         h->fd_array[r].events=0; /* clear the events */
00950                                         continue;
00951                                 }
00952                                 h->crt_fd_array_idx=r;
00953                                 /* repeat handle_io if repeat, fd still watched (not deleted
00954                                  *  inside handle_io), handle_io returns that there's still
00955                                  *  IO and the fd is still watched for the triggering event */
00956                                 while(fm->type && 
00957                                                 (handle_io(fm, h->fd_array[r].revents, r) > 0) &&
00958                                                 repeat && ((fm->events|POLLERR|POLLHUP) &
00959                                                                                                         h->fd_array[r].revents));
00960                                 r=h->crt_fd_array_idx; /* can change due to io_watch_del(fd) 
00961                                                                                   array shifting */
00962                         }
00963                 }
00964 error:
00965         return ret;
00966 }
00967 
00968 
00969 
00970 #ifdef HAVE_SELECT
00971 /* wait for io using select */
00972 inline static int io_wait_loop_select(io_wait_h* h, int t, int repeat)
00973 {
00974         fd_set sel_rset;
00975         fd_set sel_wset;
00976         int n, ret;
00977         struct timeval timeout;
00978         int r;
00979         struct fd_map* fm;
00980         int revents;
00981         
00982 again:
00983                 sel_rset=h->master_rset;
00984                 sel_wset=h->master_wset;
00985                 timeout.tv_sec=t;
00986                 timeout.tv_usec=0;
00987                 ret=n=select(h->max_fd_select+1, &sel_rset, &sel_wset, 0, &timeout);
00988                 if (n<0){
00989                         if (errno==EINTR) goto again; /* just a signal */
00990                         LOG(L_ERR, "ERROR: io_wait_loop_select: select: %s [%d]\n",
00991                                         strerror(errno), errno);
00992                         n=0;
00993                         /* continue */
00994                 }
00995                 /* use poll fd array */
00996                 for(r=0; (r<h->fd_no) && n; r++){
00997                         revents=0;
00998                         if (likely(FD_ISSET(h->fd_array[r].fd, &sel_rset)))
00999                                 revents|=POLLIN;
01000                         if (unlikely(FD_ISSET(h->fd_array[r].fd, &sel_wset)))
01001                                 revents|=POLLOUT;
01002                         if (unlikely(revents)){
01003                                 h->crt_fd_array_idx=r;
01004                                 fm=get_fd_map(h, h->fd_array[r].fd);
01005                                 while(fm->type && (fm->events & revents) && 
01006                                                 (handle_io(fm, revents, r)>0) && repeat);
01007                                 r=h->crt_fd_array_idx; /* can change due to io_watch_del(fd) 
01008                                                                                   array shifting */
01009                                 n--;
01010                         }
01011                 };
01012         return ret;
01013 }
01014 #endif
01015 
01016 
01017 
01018 #ifdef HAVE_EPOLL
01019 inline static int io_wait_loop_epoll(io_wait_h* h, int t, int repeat)
01020 {
01021         int n, r;
01022         struct fd_map* fm;
01023         int revents;
01024         
01025 again:
01026                 n=epoll_wait(h->epfd, h->ep_array, h->fd_no, t*1000);
01027                 if (unlikely(n==-1)){
01028                         if (errno==EINTR) goto again; /* signal, ignore it */
01029                         else{
01030                                 LOG(L_ERR, "ERROR:io_wait_loop_epoll: "
01031                                                 "epoll_wait(%d, %p, %d, %d): %s [%d]\n", 
01032                                                 h->epfd, h->ep_array, h->fd_no, t*1000,
01033                                                 strerror(errno), errno);
01034                                 goto error;
01035                         }
01036                 }
01037 #if 0
01038                 if (n>1){
01039                         for(r=0; r<n; r++){
01040                                 LOG(L_ERR, "WARNING: ep_array[%d]= %x, %p\n",
01041                                                 r, h->ep_array[r].events, h->ep_array[r].data.ptr);
01042                         }
01043                 }
01044 #endif
01045                 for (r=0; r<n; r++){
01046                         revents= (POLLIN & (!(h->ep_array[r].events & (EPOLLIN|EPOLLPRI))
01047                                                 -1)) |
01048                                          (POLLOUT & (!(h->ep_array[r].events & EPOLLOUT)-1)) |
01049                                          (POLLERR & (!(h->ep_array[r].events & EPOLLERR)-1)) |
01050                                          (POLLHUP & (!(h->ep_array[r].events & EPOLLHUP)-1))
01051 #ifdef POLLRDHUP
01052                                         | (POLLRDHUP & (!(h->ep_array[r].events & EPOLLRDHUP)-1))
01053 #endif
01054                                         ;
01055                         if (likely(revents)){
01056                                 fm=(struct fd_map*)h->ep_array[r].data.ptr;
01057                                 while(fm->type && ((fm->events|POLLERR|POLLHUP) & revents) && 
01058                                                 (handle_io(fm, revents, -1)>0) && repeat);
01059                         }else{
01060                                 LOG(L_ERR, "ERROR:io_wait_loop_epoll: unexpected event %x"
01061                                                         " on %d/%d, data=%p\n", h->ep_array[r].events,
01062                                                         r+1, n, h->ep_array[r].data.ptr);
01063                         }
01064                 }
01065 error:
01066         return n;
01067 }
01068 #endif
01069 
01070 
01071 
01072 #ifdef HAVE_KQUEUE
01073 inline static int io_wait_loop_kqueue(io_wait_h* h, int t, int repeat)
01074 {
01075         int n, r;
01076         struct timespec tspec;
01077         struct fd_map* fm;
01078         int revents;
01079         
01080         tspec.tv_sec=t;
01081         tspec.tv_nsec=0;
01082 again:
01083                 n=kevent(h->kq_fd, h->kq_changes, h->kq_nchanges,  h->kq_array,
01084                                         h->fd_no, &tspec);
01085                 if (unlikely(n==-1)){
01086                         if (errno==EINTR) goto again; /* signal, ignore it */
01087                         else{
01088                                 LOG(L_ERR, "ERROR: io_wait_loop_kqueue: kevent:"
01089                                                 " %s [%d]\n", strerror(errno), errno);
01090                                 goto error;
01091                         }
01092                 }
01093                 h->kq_nchanges=0; /* reset changes array */
01094                 for (r=0; r<n; r++){
01095 #ifdef EXTRA_DEBUG
01096                         DBG("DBG: kqueue: event %d/%d: fd=%d, udata=%lx, flags=0x%x\n",
01097                                         r, n, h->kq_array[r].ident, (long)h->kq_array[r].udata,
01098                                         h->kq_array[r].flags);
01099 #endif
01100 #if 0
01101                         if (unlikely(h->kq_array[r].flags & EV_ERROR)){
01102                                 /* error in changes: we ignore it, it can be caused by
01103                                    trying to remove an already closed fd: race between
01104                                    adding something to the changes array, close() and
01105                                    applying the changes */
01106                                 LOG(L_INFO, "INFO: io_wait_loop_kqueue: kevent error on "
01107                                                         "fd %ld: %s [%ld]\n", h->kq_array[r].ident,
01108                                                         strerror(h->kq_array[r].data),
01109                                                         (long)h->kq_array[r].data);
01110                         }else{ 
01111 #endif
01112                                 fm=(struct fd_map*)h->kq_array[r].udata;
01113                                 if (likely(h->kq_array[r].filter==EVFILT_READ)){
01114                                         revents=POLLIN | 
01115                                                 (((int)!(h->kq_array[r].flags & EV_EOF)-1)&POLLHUP);
01116                                         while(fm->type && (fm->events & revents) && 
01117                                                         (handle_io(fm, revents, -1)>0) && repeat);
01118                                 }else if (h->kq_array[r].filter==EVFILT_WRITE){
01119                                         revents=POLLOUT | 
01120                                                 (((int)!(h->kq_array[r].flags & EV_EOF)-1)&POLLHUP);
01121                                         while(fm->type && (fm->events & revents) && 
01122                                                         (handle_io(fm, revents, -1)>0) && repeat);
01123                                 }
01124                         /*} */
01125                 }
01126 error:
01127         return n;
01128 }
01129 #endif
01130 
01131 
01132 
01133 #ifdef HAVE_SIGIO_RT
01134 /* sigio rt version has no repeat (it doesn't make sense)*/
01135 inline static int io_wait_loop_sigio_rt(io_wait_h* h, int t)
01136 {
01137         int n;
01138         int ret;
01139         struct timespec ts;
01140         siginfo_t siginfo;
01141         int sigio_band;
01142         int sigio_fd;
01143         struct fd_map* fm;
01144         int revents;
01145 #ifdef SIGINFO64_WORKARROUND
01146         int* pi;
01147 #endif
01148         
01149         
01150         ret=1; /* 1 event per call normally */
01151         ts.tv_sec=t;
01152         ts.tv_nsec=0;
01153         if (unlikely(!sigismember(&h->sset, h->signo) ||
01154                                         !sigismember(&h->sset, SIGIO))) {
01155                 LOG(L_CRIT, "BUG: io_wait_loop_sigio_rt: the signal mask"
01156                                 " is not properly set!\n");
01157                 goto error;
01158         }
01159 again:
01160         n=sigtimedwait(&h->sset, &siginfo, &ts);
01161         if (unlikely(n==-1)){
01162                 if (errno==EINTR) goto again; /* some other signal, ignore it */
01163                 else if (errno==EAGAIN){ /* timeout */
01164                         ret=0;
01165                         goto end;
01166                 }else{
01167                         LOG(L_ERR, "ERROR: io_wait_loop_sigio_rt: sigtimed_wait"
01168                                         " %s [%d]\n", strerror(errno), errno);
01169                         goto error;
01170                 }
01171         }
01172         if (likely(n!=SIGIO)){
01173 #ifdef SIGINFO64_WORKARROUND
01174                 /* on linux siginfo.si_band is defined as long in userspace
01175                  * and as int in kernel (< 2.6.5) => on 64 bits things will break!
01176                  * (si_band will include si_fd, and si_fd will contain
01177                  *  garbage).
01178                  *  see /usr/src/linux/include/asm-generic/siginfo.h and
01179                  *      /usr/include/bits/siginfo.h
01180                  *  On newer kernels this is fixed (si_band is long in the kernel too).
01181                  * -- andrei */
01182                 if  ((_os_ver<0x020605) && (sizeof(siginfo.si_band)>sizeof(int))){
01183                         pi=(int*)(void*)&siginfo.si_band; /* avoid type punning warnings */
01184                         sigio_band=*pi;
01185                         sigio_fd=*(pi+1);
01186                 }else
01187 #endif
01188                 {
01189                         sigio_band=siginfo.si_band;
01190                         sigio_fd=siginfo.si_fd;
01191                 }
01192                 if (unlikely(siginfo.si_code==SI_SIGIO)){
01193                         /* old style, we don't know the event (linux 2.2.?) */
01194                         LOG(L_WARN, "WARNING: io_wait_loop_sigio_rt: old style sigio"
01195                                         " interface\n");
01196                         fm=get_fd_map(h, sigio_fd);
01197                         /* we can have queued signals generated by fds not watched
01198                          * any more, or by fds in transition, to a child => ignore them*/
01199                         if (fm->type)
01200                                 handle_io(fm, POLLIN|POLLOUT, -1);
01201                 }else{
01202                         /* si_code contains the SIGPOLL reason: POLL_IN, POLL_OUT,
01203                          *  POLL_MSG, POLL_ERR, POLL_PRI or POLL_HUP
01204                          * and si_band the translated poll event bitmap:
01205                          *  POLLIN|POLLRDNORM  (=POLL_IN),
01206                          *  POLLOUT|POLLWRNORM|POLLWRBAND (=POLL_OUT),
01207                          *  POLLIN|POLLRDNORM|POLLMSG (=POLL_MSG),
01208                          *  POLLERR (=POLL_ERR),
01209                          *  POLLPRI|POLLRDBAND (=POLL_PRI),
01210                          *  POLLHUP|POLLERR (=POLL_HUP) 
01211                          *  [linux 2.6.22 fs/fcntl.c:447]
01212                          */
01213 #ifdef EXTRA_DEBUG
01214                         DBG("io_wait_loop_sigio_rt: siginfo: signal=%d (%d),"
01215                                         " si_code=%d, si_band=0x%x,"
01216                                         " si_fd=%d\n",
01217                                         siginfo.si_signo, n, siginfo.si_code, 
01218                                         (unsigned)sigio_band,
01219                                         sigio_fd);
01220 #endif
01221                         /* on some errors (e.g. when receving TCP RST), sigio_band will
01222                          * be set to 0x08 (POLLERR) or 0x18 (POLLERR|POLLHUP - on stream
01223                          *  unix socket close) , so better catch all events --andrei */
01224                         if (likely(sigio_band)){
01225                                 fm=get_fd_map(h, sigio_fd);
01226                                 revents=sigio_band;
01227                                 /* fix revents==POLLPRI case */
01228                                 revents |= (!(revents & POLLPRI)-1) & POLLIN;
01229                                 /* we can have queued signals generated by fds not watched
01230                                  * any more, or by fds in transition, to a child 
01231                                  * => ignore them */
01232                                 if (fm->type && ((fm->events|POLLERR|POLLHUP) & revents))
01233                                         handle_io(fm, revents, -1);
01234                                 else
01235                                         DBG("WARNING: io_wait_loop_sigio_rt: ignoring event"
01236                                                         " %x on fd %d, watching for %x, si_code=%x "
01237                                                         "(fm->type=%d, fm->fd=%d, fm->data=%p)\n",
01238                                                         sigio_band, sigio_fd, fm->events, siginfo.si_code,
01239                                                         fm->type, fm->fd, fm->data);
01240                         }else{
01241                                 LOG(L_ERR, "ERROR: io_wait_loop_sigio_rt: unexpected event"
01242                                                         " on fd %d: %x\n", sigio_fd, sigio_band);
01243                         }
01244                 }
01245         }else{
01246                 /* signal queue overflow 
01247                  * TODO: increase signal queue size: 2.4x /proc/.., 2.6x -rlimits */
01248                 LOG(L_WARN, "WARNING: io_wait_loop_sigio_rt: signal queue overflowed"
01249                                         "- falling back to poll\n");
01250                 /* clear real-time signal queue
01251                  * both SIG_IGN and SIG_DFL are needed , it doesn't work
01252                  * only with SIG_DFL  */
01253                 if (signal(h->signo, SIG_IGN)==SIG_ERR){
01254                         LOG(L_CRIT, "BUG: do_poll: couldn't reset signal to IGN\n");
01255                 }
01256                 
01257                 if (signal(h->signo, SIG_DFL)==SIG_ERR){
01258                         LOG(L_CRIT, "BUG: do_poll: couldn't reset signal to DFL\n");
01259                 }
01260                 /* falling back to normal poll */
01261                 ret=io_wait_loop_poll(h, -1, 1);
01262         }
01263 end:
01264         return ret;
01265 error:
01266         return -1;
01267 }
01268 #endif
01269 
01270 
01271 
01272 #ifdef HAVE_DEVPOLL
01273 inline static int io_wait_loop_devpoll(io_wait_h* h, int t, int repeat)
01274 {
01275         int n, r;
01276         int ret;
01277         struct dvpoll dpoll;
01278         struct fd_map* fm;
01279 
01280                 dpoll.dp_timeout=t*1000;
01281                 dpoll.dp_nfds=h->fd_no;
01282                 dpoll.dp_fds=h->fd_array;
01283 again:
01284                 ret=n=ioctl(h->dpoll_fd, DP_POLL, &dpoll);
01285                 if (unlikely(n==-1)){
01286                         if (errno==EINTR) goto again; /* signal, ignore it */
01287                         else{
01288                                 LOG(L_ERR, "ERROR:io_wait_loop_devpoll: ioctl: %s [%d]\n",
01289                                                 strerror(errno), errno);
01290                                 goto error;
01291                         }
01292                 }
01293                 for (r=0; r< n; r++){
01294                         if (h->fd_array[r].revents & (POLLNVAL|POLLERR)){
01295                                 LOG(L_ERR, "ERROR: io_wait_loop_devpoll: pollinval returned"
01296                                                         " for fd %d, revents=%x\n",
01297                                                         h->fd_array[r].fd, h->fd_array[r].revents);
01298                         }
01299                         /* POLLIN|POLLHUP just go through */
01300                         fm=get_fd_map(h, h->fd_array[r].fd);
01301                         while(fm->type && (fm->events & h->fd_array[r].revents) &&
01302                                         (handle_io(fm, h->fd_array[r].revents, r) > 0) && repeat);
01303                 }
01304 error:
01305         return ret;
01306 }
01307 #endif
01308 
01309 
01310 
01311 /* init */
01312 
01313 
01314 /* initializes the static vars/arrays
01315  * params:      h - pointer to the io_wait_h that will be initialized
01316  *         max_fd - maximum allowed fd number
01317  *         poll_m - poll method (0 for automatic best fit)
01318  */
01319 int init_io_wait(io_wait_h* h, int max_fd, enum poll_types poll_method);
01320 
01321 /* destroys everything init_io_wait allocated */
01322 void destroy_io_wait(io_wait_h* h);
01323 
01324 
01325 #endif

Generated on Thu Sep 9 04:15:43 2010 for SIPExpressRouter by  doxygen 1.3.9.1