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