Happy new year
[yaz-moved-to-github.git] / src / poll.c
1 /* This file is part of the YAZ toolkit.
2  * Copyright (C) 1995-2009 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         if (mask & yaz_poll_read)
67             FD_SET(fd, &input);
68         if (mask & yaz_poll_write)
69             FD_SET(fd, &output);
70         if (mask & yaz_poll_except)
71             FD_SET(fd, &except);
72         if (max_fd < fd)
73             max_fd = fd;
74     }
75     tv.tv_sec = sec;
76     tv.tv_usec = nsec / 1000;
77     
78     r = select(max_fd+1, &input, &output, &except, (sec == -1 ? 0 : &tv));
79     if (r >= 0)
80     {
81         for (i = 0; i < num_fds; i++)
82         {
83             enum yaz_poll_mask mask = yaz_poll_none;
84             int fd = fds[i].fd;
85             if (!r)
86                 yaz_poll_add(mask, yaz_poll_timeout);
87             else
88             {
89                 if (FD_ISSET(fd, &input))
90                     yaz_poll_add(mask, yaz_poll_read);
91                 if (FD_ISSET(fd, &output))
92                     yaz_poll_add(mask, yaz_poll_write);
93                 if (FD_ISSET(fd, &except))
94                     yaz_poll_add(mask, yaz_poll_except);
95             }
96             fds[i].output_mask = mask;
97         }
98     }
99     return r;
100 }
101
102 #if HAVE_SYS_POLL_H
103 int yaz_poll_poll(struct yaz_poll_fd *fds, int num_fds, int sec, int nsec)
104 {
105     int r;
106     struct pollfd *pollfds = (struct pollfd *) 
107         xmalloc(num_fds * sizeof *pollfds);
108     int i;
109
110     assert(num_fds > 0);
111     for (i = 0; i < num_fds; i++)
112     {
113         enum yaz_poll_mask mask = fds[i].input_mask;
114         int fd = fds[i].fd;
115         short poll_events = 0;
116
117         if (mask & yaz_poll_read)
118             poll_events += POLLIN;
119         if (mask & yaz_poll_write)
120             poll_events += POLLOUT;
121         if (mask & yaz_poll_except)
122             poll_events += POLLERR;
123         pollfds[i].fd = fd;
124         pollfds[i].events = poll_events;
125         pollfds[i].revents = 0;
126     }
127     r = poll(pollfds, num_fds, sec == -1 ? -1 : sec*1000 + nsec/1000000);
128     if (r >= 0)
129     {
130         for (i = 0; i < num_fds; i++)
131         {
132             enum yaz_poll_mask mask = yaz_poll_none;
133             if (!r)
134                 yaz_poll_add(mask, yaz_poll_timeout);
135             else
136             {
137                 if (pollfds[i].revents & POLLIN)
138                     yaz_poll_add(mask, yaz_poll_read);
139                 if (pollfds[i].revents & POLLOUT)
140                     yaz_poll_add(mask, yaz_poll_write);
141                 if (pollfds[i].revents & ~(POLLIN | POLLOUT))
142                 {
143                     yaz_poll_add(mask, yaz_poll_except);
144                 }
145             }
146             fds[i].output_mask = mask;
147         }
148     }
149     xfree(pollfds);
150     return r;
151 }
152 #endif
153
154 int yaz_poll(struct yaz_poll_fd *fds, int num_fds, int sec, int nsec)
155 {
156 #if YAZ_HAVE_SYS_POLL_H
157     return yaz_poll_poll(fds, num_fds, sec, nsec);
158 #else
159     return yaz_poll_select(fds, num_fds, sec, nsec);
160 #endif
161 }
162
163 /*
164  * Local variables:
165  * c-basic-offset: 4
166  * indent-tabs-mode: nil
167  * End:
168  * vim: shiftwidth=4 tabstop=8 expandtab
169  */
170