Doxyfile file description. Indentation. No change of code.
[yaz-moved-to-github.git] / src / eventl.c
1 /*
2  * Copyright (c) 1995-2004, Index Data
3  * See the file LICENSE for details.
4  *
5  * $Id: eventl.c,v 1.2 2004-10-15 00:19:00 adam Exp $
6  */
7
8 /**
9  * \file eventl.c
10  * \brief Implements event loop handling for GFS.
11  *
12  * This source implements the main event loop for the Generic Frontend
13  * Server. It uses select(2).
14  */
15
16 #include <stdio.h>
17 #include <assert.h>
18 #ifdef WIN32
19 #include <winsock.h>
20 #else
21 #include <unistd.h>
22 #endif
23 #include <stdlib.h>
24 #include <errno.h>
25 #include <string.h>
26
27 #include <yaz/yconfig.h>
28 #include <yaz/log.h>
29 #include <yaz/comstack.h>
30 #include <yaz/xmalloc.h>
31 #include "eventl.h"
32 #include "session.h"
33 #include <yaz/statserv.h>
34
35 #if YAZ_GNU_THREADS
36 #include <pth.h>
37 #define YAZ_EV_SELECT pth_select
38 #endif
39
40 #ifndef YAZ_EV_SELECT
41 #define YAZ_EV_SELECT select
42 #endif
43
44 IOCHAN iochan_create(int fd, IOC_CALLBACK cb, int flags)
45 {
46     IOCHAN new_iochan;
47
48     if (!(new_iochan = (IOCHAN)xmalloc(sizeof(*new_iochan))))
49         return 0;
50     new_iochan->destroyed = 0;
51     new_iochan->fd = fd;
52     new_iochan->flags = flags;
53     new_iochan->fun = cb;
54     new_iochan->force_event = 0;
55     new_iochan->last_event = new_iochan->max_idle = 0;
56     new_iochan->next = NULL;
57     return new_iochan;
58 }
59
60 int event_loop(IOCHAN *iochans)
61 {
62     do /* loop as long as there are active associations to process */
63     {
64         IOCHAN p, nextp;
65         fd_set in, out, except;
66         int res, max;
67         static struct timeval to;
68         time_t now = time(0);
69
70         if (statserv_must_terminate())
71         {
72             for (p = *iochans; p; p = p->next)
73                 p->force_event = EVENT_TIMEOUT;
74         }
75         FD_ZERO(&in);
76         FD_ZERO(&out);
77         FD_ZERO(&except);
78         to.tv_sec = 3600;
79         to.tv_usec = 0;
80         max = 0;
81         for (p = *iochans; p; p = p->next)
82         {
83             time_t w, ftime;
84             yaz_log(LOG_DEBUG, "fd=%d flags=%d force_event=%d",
85                     p->fd, p->flags, p->force_event);
86             if (p->force_event)
87                 to.tv_sec = 0;          /* polling select */
88             if (p->flags & EVENT_INPUT)
89                 FD_SET(p->fd, &in);
90             if (p->flags & EVENT_OUTPUT)
91                 FD_SET(p->fd, &out);
92             if (p->flags & EVENT_EXCEPT)
93                 FD_SET(p->fd, &except);
94             if (p->fd > max)
95                 max = p->fd;
96             if (p->max_idle && p->last_event)
97             {
98                 ftime = p->last_event + p->max_idle;
99                 if (ftime < now)
100                     w = p->max_idle;
101                 else
102                     w = ftime - now;
103                 if (w < to.tv_sec)
104                     to.tv_sec = w;
105             }
106         }
107         yaz_log(LOG_DEBUG, "select start %ld", (long) to.tv_sec);
108         res = YAZ_EV_SELECT(max + 1, &in, &out, &except, &to);
109         yaz_log(LOG_DEBUG, "select end");
110         if (res < 0)
111         {
112             if (yaz_errno() == EINTR)
113             {
114                 if (statserv_must_terminate())
115                 {
116                     for (p = *iochans; p; p = p->next)
117                         p->force_event = EVENT_TIMEOUT;
118                 }
119                 continue;
120             }
121             else
122             {
123                 /* Destroy the first member in the chain, and try again */
124                 association *assoc = (association *)iochan_getdata(*iochans);
125                 COMSTACK conn = assoc->client_link;
126
127                 cs_close(conn);
128                 destroy_association(assoc);
129                 iochan_destroy(*iochans);
130                 yaz_log(LOG_DEBUG, "error select, destroying iochan %p",
131                         *iochans);
132             }
133         }
134         now = time(0);
135         for (p = *iochans; p; p = p->next)
136         {
137             int force_event = p->force_event;
138
139             p->force_event = 0;
140             if (!p->destroyed && (FD_ISSET(p->fd, &in) ||
141                 force_event == EVENT_INPUT))
142             {
143                 p->last_event = now;
144                 (*p->fun)(p, EVENT_INPUT);
145             }
146             if (!p->destroyed && (FD_ISSET(p->fd, &out) ||
147                 force_event == EVENT_OUTPUT))
148             {
149                 p->last_event = now;
150                 (*p->fun)(p, EVENT_OUTPUT);
151             }
152             if (!p->destroyed && (FD_ISSET(p->fd, &except) ||
153                 force_event == EVENT_EXCEPT))
154             {
155                 p->last_event = now;
156                 (*p->fun)(p, EVENT_EXCEPT);
157             }
158             if (!p->destroyed && ((p->max_idle && now - p->last_event >=
159                 p->max_idle) || force_event == EVENT_TIMEOUT))
160             {
161                 p->last_event = now;
162                 (*p->fun)(p, EVENT_TIMEOUT);
163             }
164         }
165         for (p = *iochans; p; p = nextp)
166         {
167             nextp = p->next;
168
169             if (p->destroyed)
170             {
171                 IOCHAN tmp = p, pr;
172
173                 /* We need to inform the threadlist that this channel has been destroyed */
174                 statserv_remove(p);
175
176                 /* Now reset the pointers */
177                 if (p == *iochans)
178                     *iochans = p->next;
179                 else
180                 {
181                     for (pr = *iochans; pr; pr = pr->next)
182                         if (pr->next == p)
183                             break;
184                     assert(pr); /* grave error if it weren't there */
185                     pr->next = p->next;
186                 }
187                 if (nextp == p)
188                     nextp = p->next;
189                 xfree(tmp);
190             }
191         }
192     }
193     while (*iochans);
194     return 0;
195 }