08e5d4671a6032edf14c63a6b5996e2d1a2b191e
[yaz-moved-to-github.git] / src / poll.c
1 /* This file is part of the YAZ toolkit.
2  * Copyright (C) 1995-2010 Index Data
3  * See the file LICENSE for details.
4  */
5 /**
6  * \file 
7  * \brief Select, poll wrapper
8  */
9
10 #include <assert.h>
11 #include <string.h>
12 #include <errno.h>
13
14 #include <yaz/log.h>
15 #include <yaz/xmalloc.h>
16 #include <yaz/poll.h>
17
18 #if HAVE_SYS_TYPES_H
19 #include <sys/types.h>
20 #endif
21 #if HAVE_SYS_TIME_H
22 #include <sys/time.h>
23 #endif
24 #if HAVE_SYS_POLL_H
25 #include <sys/poll.h>
26 #endif
27 #if HAVE_SYS_SELECT_H
28 #include <sys/select.h>
29 #endif
30 #ifdef WIN32
31 #if FD_SETSIZE < 512
32 #define FD_SETSIZE 512
33 #endif
34 #include <winsock.h>
35 #endif
36
37 /*
38   Note that yaz_poll_select is limited as to how many file
39   descriptors it can multiplex due to its use of select() which in
40   turn uses the statically defined fd_set type to be a bitmap of the
41   file descriptors to check.  On Ubuntu 6.06 (and almost certainly on
42   Debian, and probably on all Linuxes, and maybe all Unixes) this is
43   by default set to 1024 (though it may be possible to override this
44   using a #define before including <sys/select.h> -- I've not tried
45   this).  1024 file descriptors is a lot, but not enough in all
46   cases, e.g. when running IRSpy on a large target database.  So you
47   should ensure that YAZ uses ZOOM_yaz_poll_poll() when possible.
48 */
49 int yaz_poll_select(struct yaz_poll_fd *fds, int num_fds, int sec, int nsec)
50 {
51     struct timeval tv;
52     fd_set input, output, except;
53     int i, r;
54     int max_fd = 0;
55
56     FD_ZERO(&input);
57     FD_ZERO(&output);
58     FD_ZERO(&except);
59
60     assert(num_fds > 0);
61     for (i = 0; i < num_fds; i++)
62     {
63         enum yaz_poll_mask mask = fds[i].input_mask;
64         int fd = fds[i].fd;
65
66         /* Timeout events */
67         if (fd < 0)
68             continue;
69
70         if (mask & yaz_poll_read)
71             FD_SET(fd, &input);
72         if (mask & yaz_poll_write)
73             FD_SET(fd, &output);
74         if (mask & yaz_poll_except)
75             FD_SET(fd, &except);
76         if (max_fd < fd)
77             max_fd = fd;
78     }
79     tv.tv_sec = sec;
80     tv.tv_usec = nsec / 1000;
81     
82     r = select(max_fd+1, &input, &output, &except, (sec == -1 ? 0 : &tv));
83     if (r >= 0)
84     {
85         for (i = 0; i < num_fds; i++)
86         {
87             enum yaz_poll_mask mask = yaz_poll_none;
88             int fd = fds[i].fd;
89             if (!r)
90                 yaz_poll_add(mask, yaz_poll_timeout);
91             else if (fd >= 0) {
92                 if (FD_ISSET(fd, &input))
93                     yaz_poll_add(mask, yaz_poll_read);
94                 if (FD_ISSET(fd, &output))
95                     yaz_poll_add(mask, yaz_poll_write);
96                 if (FD_ISSET(fd, &except))
97                     yaz_poll_add(mask, yaz_poll_except);
98             }
99             fds[i].output_mask = mask;
100         }
101     }
102     return r;
103 }
104
105 #if HAVE_SYS_POLL_H
106 int yaz_poll_poll(struct yaz_poll_fd *fds, int num_fds, int sec, int nsec)
107 {
108     int r;
109     struct pollfd *pollfds = (struct pollfd *) 
110         xmalloc(num_fds * sizeof *pollfds);
111     int i;
112
113     assert(num_fds > 0);
114     for (i = 0; i < num_fds; i++)
115     {
116         enum yaz_poll_mask mask = fds[i].input_mask;
117         int fd = fds[i].fd;
118         short poll_events = 0;
119
120         if (mask & yaz_poll_read)
121             poll_events += POLLIN;
122         if (mask & yaz_poll_write)
123             poll_events += POLLOUT;
124         if (mask & yaz_poll_except)
125             poll_events += POLLERR;
126         pollfds[i].fd = fd;
127         pollfds[i].events = poll_events;
128         pollfds[i].revents = 0;
129     }
130     r = poll(pollfds, num_fds, sec == -1 ? -1 : sec*1000 + nsec/1000000);
131     if (r >= 0)
132     {
133         for (i = 0; i < num_fds; i++)
134         {
135             enum yaz_poll_mask mask = yaz_poll_none;
136             if (!r)
137                 yaz_poll_add(mask, yaz_poll_timeout);
138             else
139             {
140                 if (pollfds[i].revents & POLLIN)
141                     yaz_poll_add(mask, yaz_poll_read);
142                 if (pollfds[i].revents & POLLOUT)
143                     yaz_poll_add(mask, yaz_poll_write);
144                 if (pollfds[i].revents & ~(POLLIN | POLLOUT))
145                 {
146                     yaz_poll_add(mask, yaz_poll_except);
147                 }
148             }
149             fds[i].output_mask = mask;
150         }
151     }
152     xfree(pollfds);
153     return r;
154 }
155 #endif
156
157 int yaz_poll(struct yaz_poll_fd *fds, int num_fds, int sec, int nsec)
158 {
159 #if YAZ_HAVE_SYS_POLL_H
160     return yaz_poll_poll(fds, num_fds, sec, nsec);
161 #else
162     return yaz_poll_select(fds, num_fds, sec, nsec);
163 #endif
164 }
165
166 /*
167  * Local variables:
168  * c-basic-offset: 4
169  * c-file-style: "Stroustrup"
170  * indent-tabs-mode: nil
171  * End:
172  * vim: shiftwidth=4 tabstop=8 expandtab
173  */
174