Added include of sys/time.h
[pazpar2-moved-to-github.git] / src / eventl.c
1 /* $Id: eventl.c,v 1.7 2007-07-09 19:30:35 adam Exp $
2    Copyright (c) 2006-2007, Index Data.
3
4 This file is part of Pazpar2.
5
6 Pazpar2 is free software; you can redistribute it and/or modify it under
7 the terms of the GNU General Public License as published by the Free
8 Software Foundation; either version 2, or (at your option) any later
9 version.
10
11 Pazpar2 is distributed in the hope that it will be useful, but WITHOUT ANY
12 WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14 for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with Pazpar2; see the file LICENSE.  If not, write to the
18 Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
19 02111-1307, USA.
20  */
21
22 /*
23  * Based on  ParaZ - a simple tool for harvesting performance data for
24  * parallel operations using Z39.50.
25  * Copyright (c) 2000-2004 Index Data ApS
26  * See LICENSE file for details.
27  */
28
29 /*
30  * Based on revision YAZ' server/eventl.c 1.29.
31  */
32
33 #include <stdio.h>
34 #include <assert.h>
35
36 #if HAVE_CONFIG_H
37 #include <cconfig.h>
38 #endif
39
40 #ifdef WIN32
41 #include <winsock.h>
42 #else
43 #include <unistd.h>
44 #endif
45 #include <sys/time.h>
46 #include <stdlib.h>
47 #include <errno.h>
48 #include <string.h>
49
50 #include <yaz/yconfig.h>
51 #include <yaz/log.h>
52 #include <yaz/comstack.h>
53 #include <yaz/xmalloc.h>
54 #include "eventl.h"
55 #include <yaz/statserv.h>
56
57 IOCHAN iochan_create(int fd, IOC_CALLBACK cb, int flags)
58 {
59     IOCHAN new_iochan;
60
61     if (!(new_iochan = (IOCHAN)xmalloc(sizeof(*new_iochan))))
62         return 0;
63     new_iochan->destroyed = 0;
64     new_iochan->fd = fd;
65     new_iochan->flags = flags;
66     new_iochan->fun = cb;
67     new_iochan->force_event = 0;
68     new_iochan->last_event = new_iochan->max_idle = 0;
69     new_iochan->next = NULL;
70     return new_iochan;
71 }
72
73 int event_loop(IOCHAN *iochans)
74 {
75     do /* loop as long as there are active associations to process */
76     {
77         IOCHAN p, nextp;
78         fd_set in, out, except;
79         int res, max;
80         static struct timeval nullto = {0, 0}, to;
81         struct timeval *timeout;
82
83         FD_ZERO(&in);
84         FD_ZERO(&out);
85         FD_ZERO(&except);
86         timeout = &to; /* hang on select */
87         to.tv_sec = 30;
88         to.tv_usec = 0;
89         max = 0;
90         for (p = *iochans; p; p = p->next)
91         {
92             if (p->fd < 0)
93                 continue;
94             if (p->force_event)
95                 timeout = &nullto;        /* polling select */
96             if (p->flags & EVENT_INPUT)
97                 FD_SET(p->fd, &in);
98             if (p->flags & EVENT_OUTPUT)
99                 FD_SET(p->fd, &out);
100             if (p->flags & EVENT_EXCEPT)
101                 FD_SET(p->fd, &except);
102             if (p->fd > max)
103                 max = p->fd;
104             if (p->max_idle && p->max_idle < to.tv_sec)
105                 to.tv_sec = p->max_idle;
106         }
107         if ((res = select(max + 1, &in, &out, &except, timeout)) < 0)
108         {
109             if (errno == EINTR)
110                 continue;
111             else
112                 abort();
113         }
114         for (p = *iochans; p; p = p->next)
115         {
116             int force_event = p->force_event;
117             time_t now = time(0);
118
119             p->force_event = 0;
120             if (!p->destroyed && ((p->max_idle && now - p->last_event >
121                 p->max_idle) || force_event == EVENT_TIMEOUT))
122             {
123                 p->last_event = now;
124                 (*p->fun)(p, EVENT_TIMEOUT);
125             }
126             if (p->fd < 0)
127                 continue;
128             if (!p->destroyed && (FD_ISSET(p->fd, &in) ||
129                 force_event == EVENT_INPUT))
130             {
131                 p->last_event = now;
132                 (*p->fun)(p, EVENT_INPUT);
133             }
134             if (!p->destroyed && (FD_ISSET(p->fd, &out) ||
135                 force_event == EVENT_OUTPUT))
136             {
137                 p->last_event = now;
138                 (*p->fun)(p, EVENT_OUTPUT);
139             }
140             if (!p->destroyed && (FD_ISSET(p->fd, &except) ||
141                 force_event == EVENT_EXCEPT))
142             {
143                 p->last_event = now;
144                 (*p->fun)(p, EVENT_EXCEPT);
145             }
146         }
147         for (p = *iochans; p; p = nextp)
148         {
149             nextp = p->next;
150
151             if (p->destroyed)
152             {
153                 IOCHAN tmp = p, pr;
154
155                 /* Now reset the pointers */
156                 if (p == *iochans)
157                     *iochans = p->next;
158                 else
159                 {
160                     for (pr = *iochans; pr; pr = pr->next)
161                         if (pr->next == p)
162                             break;
163                     assert(pr); /* grave error if it weren't there */
164                     pr->next = p->next;
165                 }
166                 if (nextp == p)
167                     nextp = p->next;
168                 xfree(tmp);
169             }
170         }
171     }
172     while (*iochans);
173     return 0;
174 }
175
176 /*
177  * Local variables:
178  * c-basic-offset: 4
179  * indent-tabs-mode: nil
180  * End:
181  * vim: shiftwidth=4 tabstop=8 expandtab
182  */