00001
00002
00003
00004
00005
00014 #include <assert.h>
00015 #include <errno.h>
00016 #include <stdio.h>
00017 #include <stdlib.h>
00018 #include <string.h>
00019
00020 #if HAVE_SYS_TYPES_H
00021 #include <sys/types.h>
00022 #endif
00023 #if HAVE_SYS_TIME_H
00024 #include <sys/time.h>
00025 #endif
00026
00027 #include <yaz/poll.h>
00028
00029 #include <yaz/log.h>
00030 #include <yaz/comstack.h>
00031 #include <yaz/xmalloc.h>
00032 #include "eventl.h"
00033 #include "session.h"
00034 #include <yaz/statserv.h>
00035
00036 static int log_level=0;
00037 static int log_level_initialized=0;
00038
00039 IOCHAN iochan_create(int fd, IOC_CALLBACK cb, int flags, int chan_id)
00040 {
00041 IOCHAN new_iochan;
00042
00043 if (!log_level_initialized)
00044 {
00045 log_level=yaz_log_module_level("eventl");
00046 log_level_initialized=1;
00047 }
00048
00049 if (!(new_iochan = (IOCHAN)xmalloc(sizeof(*new_iochan))))
00050 return 0;
00051 new_iochan->destroyed = 0;
00052 new_iochan->fd = fd;
00053 new_iochan->flags = flags;
00054 new_iochan->fun = cb;
00055 new_iochan->force_event = 0;
00056 new_iochan->last_event = new_iochan->max_idle = 0;
00057 new_iochan->next = NULL;
00058 new_iochan->chan_id = chan_id;
00059 return new_iochan;
00060 }
00061
00062
00063 int iochan_is_alive(IOCHAN chan)
00064 {
00065 struct yaz_poll_fd fds;
00066 int res;
00067
00068 fds.fd = chan->fd;
00069 fds.input_mask = yaz_poll_read;
00070 res = yaz_poll(&fds, 1, 0, 0);
00071 if (res == 0)
00072 return 1;
00073 if (!ir_read(chan, EVENT_INPUT))
00074 return 0;
00075 return 1;
00076 }
00077
00078 int iochan_event_loop(IOCHAN *iochans)
00079 {
00080 do
00081 {
00082 IOCHAN p, nextp;
00083 int i;
00084 int tv_sec = 3600;
00085 int no_fds = 0;
00086 struct yaz_poll_fd *fds = 0;
00087 int res;
00088 time_t now = time(0);
00089
00090 if (statserv_must_terminate())
00091 {
00092 for (p = *iochans; p; p = p->next)
00093 p->force_event = EVENT_TIMEOUT;
00094 }
00095 for (p = *iochans; p; p = p->next)
00096 no_fds++;
00097 fds = (struct yaz_poll_fd *) xmalloc(no_fds * sizeof(*fds));
00098 for (i = 0, p = *iochans; p; p = p->next, i++)
00099 {
00100 time_t w, ftime;
00101 enum yaz_poll_mask input_mask = yaz_poll_none;
00102 yaz_log(log_level, "fd=%d flags=%d force_event=%d",
00103 p->fd, p->flags, p->force_event);
00104 if (p->force_event)
00105 tv_sec = 0;
00106 if (p->flags & EVENT_INPUT)
00107 yaz_poll_add(input_mask, yaz_poll_read);
00108 if (p->flags & EVENT_OUTPUT)
00109 yaz_poll_add(input_mask, yaz_poll_write);
00110 if (p->flags & EVENT_EXCEPT)
00111 yaz_poll_add(input_mask, yaz_poll_except);
00112 if (p->max_idle && p->last_event)
00113 {
00114 ftime = p->last_event + p->max_idle;
00115 if (ftime < now)
00116 w = p->max_idle;
00117 else
00118 w = ftime - now;
00119 if (w < tv_sec)
00120 tv_sec = w;
00121 }
00122 fds[i].fd = p->fd;
00123 fds[i].input_mask = input_mask;
00124 }
00125 res = yaz_poll(fds, no_fds, tv_sec, 0);
00126 if (res < 0)
00127 {
00128 if (yaz_errno() == EINTR)
00129 {
00130 if (statserv_must_terminate())
00131 {
00132 for (p = *iochans; p; p = p->next)
00133 p->force_event = EVENT_TIMEOUT;
00134 }
00135 xfree(fds);
00136 continue;
00137 }
00138 else
00139 {
00140
00141 association *assoc = (association *)iochan_getdata(*iochans);
00142 COMSTACK conn = assoc->client_link;
00143
00144 cs_close(conn);
00145 destroy_association(assoc);
00146 iochan_destroy(*iochans);
00147 yaz_log(log_level, "error select, destroying iochan %p",
00148 *iochans);
00149 }
00150 }
00151 now = time(0);
00152 for (i = 0, p = *iochans; p; p = p->next, i++)
00153 {
00154 int force_event = p->force_event;
00155 enum yaz_poll_mask output_mask = fds[i].output_mask;
00156
00157 p->force_event = 0;
00158 if (!p->destroyed && ((output_mask & yaz_poll_read) ||
00159 force_event == EVENT_INPUT))
00160 {
00161 p->last_event = now;
00162 (*p->fun)(p, EVENT_INPUT);
00163 }
00164 if (!p->destroyed && ((output_mask & yaz_poll_write) ||
00165 force_event == EVENT_OUTPUT))
00166 {
00167 p->last_event = now;
00168 (*p->fun)(p, EVENT_OUTPUT);
00169 }
00170 if (!p->destroyed && ((output_mask & yaz_poll_except) ||
00171 force_event == EVENT_EXCEPT))
00172 {
00173 p->last_event = now;
00174 (*p->fun)(p, EVENT_EXCEPT);
00175 }
00176 if (!p->destroyed && ((p->max_idle && now - p->last_event >=
00177 p->max_idle) || force_event == EVENT_TIMEOUT))
00178 {
00179 p->last_event = now;
00180 (*p->fun)(p, EVENT_TIMEOUT);
00181 }
00182 }
00183 xfree(fds);
00184 for (p = *iochans; p; p = nextp)
00185 {
00186 nextp = p->next;
00187
00188 if (p->destroyed)
00189 {
00190 IOCHAN tmp = p, pr;
00191
00192
00193 statserv_remove(p);
00194
00195
00196 if (p == *iochans)
00197 *iochans = p->next;
00198 else
00199 {
00200 for (pr = *iochans; pr; pr = pr->next)
00201 if (pr->next == p)
00202 break;
00203 assert(pr);
00204 pr->next = p->next;
00205 }
00206 if (nextp == p)
00207 nextp = p->next;
00208 xfree(tmp);
00209 }
00210 }
00211 }
00212 while (*iochans);
00213 return 0;
00214 }
00215
00216
00217
00218
00219
00220
00221
00222