improved load balancing algorithm.
[l2tpns.git] / fake_epoll.h
1 /* kludge up some limited epoll semantics using select for 2.4 kernels */
2 /* $Id: fake_epoll.h,v 1.2 2007-06-28 07:22:50 bodea Exp $ */
3
4 #ifndef __FAKE_EPOLL_H__
5 #define __FAKE_EPOLL_H__
6
7 #define EPOLLIN 0x01
8 #define EPOLLOUT 0x04
9 #define EPOLLERR 0x08
10 #define EPOLLHUP 0x10
11
12 #define EPOLL_CTL_ADD 1
13 #define EPOLL_CTL_DEL 2
14 #define EPOLL_CTL_MOD 3
15
16 struct epoll_event {
17 uint32_t events;
18 union epoll_data {
19 void *ptr;
20 int fd;
21 uint32_t u32;
22 uint64_t u64;
23 } data;
24 };
25
26 int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
27
28 #ifdef FAKE_EPOLL_IMPLEMENTATION
29
30 #include <sys/select.h>
31
32 static fd_set _epoll_read_set;
33 static fd_set _epoll_write_set;
34 static int _epoll_fds;
35 static struct epoll_event *_epoll_data[128];
36
37 static int epoll_create(int size __attribute__ ((unused)))
38 {
39 static int once = 0;
40 if (once++)
41 {
42 errno = ENFILE; /* only support one instance */
43 return -1;
44 }
45
46 FD_ZERO(&_epoll_read_set);
47 FD_ZERO(&_epoll_write_set);
48 _epoll_fds = 0;
49
50 memset(_epoll_data, 0, sizeof(_epoll_data));
51
52 return 1; /* "descriptor" */
53 }
54
55 int epoll_ctl(int epfd __attribute__ ((unused)), int op, int fd,
56 struct epoll_event *event)
57 {
58 if (fd > (sizeof(_epoll_data)/sizeof(*_epoll_data)) - 1)
59 {
60 errno = EINVAL;
61 return -1;
62 }
63
64 switch (op)
65 {
66 case EPOLL_CTL_ADD:
67 if (event->events & EPOLLIN)
68 FD_SET(fd, &_epoll_read_set);
69
70 if (event->events & EPOLLOUT)
71 FD_SET(fd, &_epoll_write_set);
72
73 if (fd >= _epoll_fds)
74 _epoll_fds = fd + 1;
75
76 if (_epoll_data[fd])
77 free(_epoll_data[fd]);
78
79 if (!(_epoll_data[fd] = malloc(sizeof(*_epoll_data))))
80 {
81 errno = ENOMEM;
82 return -1;
83 }
84
85 memcpy(_epoll_data[fd], &event->data, sizeof(*_epoll_data));
86 break;
87
88 case EPOLL_CTL_MOD:
89 if (event->events & EPOLLIN)
90 FD_SET(fd, &_epoll_read_set);
91 else
92 FD_CLR(fd, &_epoll_read_set);
93
94 if (event->events & EPOLLOUT)
95 FD_SET(fd, &_epoll_write_set);
96 else
97 FD_CLR(fd, &_epoll_write_set);
98
99 memcpy(_epoll_data[fd], &event->data, sizeof(*_epoll_data));
100 break;
101
102 case EPOLL_CTL_DEL:
103 FD_CLR(fd, &_epoll_read_set);
104 FD_CLR(fd, &_epoll_write_set);
105
106 free(_epoll_data[fd]);
107 _epoll_data[fd] = 0;
108
109 if (fd == _epoll_fds - 1)
110 {
111 _epoll_fds = 0;
112 while (fd-- > 0)
113 {
114 if (FD_ISSET(fd, &_epoll_read_set) ||
115 FD_ISSET(fd, &_epoll_write_set))
116 {
117 _epoll_fds = fd + 1;
118 break;
119 }
120 }
121 }
122
123 break;
124 }
125
126 return 0;
127 }
128
129 static int epoll_wait(int epfd __attribute__ ((unused)),
130 struct epoll_event *events, int maxevents, int timout)
131 {
132 fd_set r;
133 fd_set w;
134 struct timeval t;
135 struct timeval *tp;
136 int n;
137 int e;
138 int i;
139
140 memcpy(&r, &_epoll_read_set, sizeof(r));
141 memcpy(&w, &_epoll_write_set, sizeof(w));
142
143 if (timout >= 0)
144 {
145 t.tv_sec = 0;
146 t.tv_usec = timout * 1000;
147 tp = &t;
148 }
149 else
150 tp = 0;
151
152 n = select(_epoll_fds, &r, &w, 0, tp);
153 if (n < 0)
154 return n;
155
156 if (n > maxevents)
157 n = maxevents;
158
159 for (i = e = 0; n > 0 && i < _epoll_fds; i++)
160 {
161 if (!_epoll_data[i])
162 continue;
163
164 events[e].events = 0;
165 if (FD_ISSET(i, &r))
166 events[e].events |= EPOLLIN;
167
168 if (FD_ISSET(i, &w))
169 events[e].events |= EPOLLOUT;
170
171 if (events[e].events)
172 {
173 memcpy(&events[e++].data, _epoll_data[i], sizeof(events[0].data));
174 n--;
175 }
176 }
177
178 return e;
179 }
180
181 #endif /* FAKE_EPOLL_IMPLEMENTATION */
182 #endif /* __FAKE_EPOLL_H__ */