v2 / thirdparty / picoev / src / picoev_epoll.c
174 lines · 147 sloc · 4.91 KB · 6fcab013ebce80e06f4193f4fd7e90243e54e9f3
Raw
1/*
2 * Copyright (c) 2009, Cybozu Labs, Inc.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * * Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above copyright notice,
11 * this list of conditions and the following disclaimer in the documentation
12 * and/or other materials provided with the distribution.
13 * * Neither the name of the <ORGANIZATION> nor the names of its contributors
14 * may be used to endorse or promote products derived from this software
15 * without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 * POSSIBILITY OF SUCH DAMAGE.
28 */
29
30#include <errno.h>
31
32// tcc needs the pragmas, because it does not support yet
33// the __EPOLL_PACKED macro, defined to be __attribute__ ((__packed__))
34#pragma pack(push, 1)
35#include <sys/epoll.h>
36#pragma pack(pop)
37
38#include <unistd.h>
39#include "picoev.h"
40
41#ifndef PICOEV_EPOLL_DEFER_DELETES
42# define PICOEV_EPOLL_DEFER_DELETES 1
43#endif
44
45typedef struct picoev_loop_epoll_st {
46 picoev_loop loop;
47 int epfd;
48 struct epoll_event events[1024];
49} picoev_loop_epoll;
50
51picoev_globals picoev;
52
53picoev_loop* picoev_create_loop(int max_timeout)
54{
55 picoev_loop_epoll* loop;
56
57 /* init parent */
58 assert(PICOEV_IS_INITED);
59 if ((loop = (picoev_loop_epoll*)malloc(sizeof(picoev_loop_epoll))) == NULL) {
60 return NULL;
61 }
62 if (picoev_init_loop_internal(&loop->loop, max_timeout) != 0) {
63 free(loop);
64 return NULL;
65 }
66
67 /* init myself */
68 if ((loop->epfd = epoll_create(picoev.max_fd)) == -1) {
69 picoev_deinit_loop_internal(&loop->loop);
70 free(loop);
71 return NULL;
72 }
73
74 loop->loop.now = time(NULL);
75 return &loop->loop;
76}
77
78int picoev_destroy_loop(picoev_loop* _loop)
79{
80 picoev_loop_epoll* loop = (picoev_loop_epoll*)_loop;
81
82 if (close(loop->epfd) != 0) {
83 return -1;
84 }
85 picoev_deinit_loop_internal(&loop->loop);
86 free(loop);
87 return 0;
88}
89
90int picoev_update_events_internal(picoev_loop* _loop, int fd, int events)
91{
92 picoev_loop_epoll* loop = (picoev_loop_epoll*)_loop;
93 picoev_fd* target = picoev.fds + fd;
94 struct epoll_event ev;
95 int epoll_ret;
96
97 memset( &ev, 0, sizeof( ev ) );
98 assert(PICOEV_FD_BELONGS_TO_LOOP(&loop->loop, fd));
99
100 if ((events & PICOEV_READWRITE) == target->events) {
101 return 0;
102 }
103
104 ev.events = ((events & PICOEV_READ) != 0 ? EPOLLIN : 0)
105 | ((events & PICOEV_WRITE) != 0 ? EPOLLOUT : 0);
106 ev.data.fd = fd;
107
108#define SET(op, check_error) do { \
109 epoll_ret = epoll_ctl(loop->epfd, op, fd, &ev); \
110 assert(! check_error || epoll_ret == 0); \
111 } while (0)
112
113#if PICOEV_EPOLL_DEFER_DELETES
114
115 if ((events & PICOEV_DEL) != 0) {
116 /* nothing to do */
117 } else if ((events & PICOEV_READWRITE) == 0) {
118 SET(EPOLL_CTL_DEL, 1);
119 } else {
120 SET(EPOLL_CTL_MOD, 0);
121 if (epoll_ret != 0) {
122 assert(errno == ENOENT);
123 SET(EPOLL_CTL_ADD, 1);
124 }
125 }
126
127#else
128
129 if ((events & PICOEV_READWRITE) == 0) {
130 SET(EPOLL_CTL_DEL, 1);
131 } else {
132 SET(target->events == 0 ? EPOLL_CTL_ADD : EPOLL_CTL_MOD, 1);
133 }
134
135#endif
136
137#undef SET
138
139 target->events = events;
140
141 return 0;
142}
143
144int picoev_poll_once_internal(picoev_loop* _loop, int max_wait)
145{
146 picoev_loop_epoll* loop = (picoev_loop_epoll*)_loop;
147 int i, nevents;
148
149 nevents = epoll_wait(loop->epfd, loop->events,
150 sizeof(loop->events) / sizeof(loop->events[0]),
151 max_wait * 1000);
152 if (nevents == -1) {
153 return -1;
154 }
155 for (i = 0; i < nevents; ++i) {
156 struct epoll_event* event = loop->events + i;
157 picoev_fd* target = picoev.fds + event->data.fd;
158 if (loop->loop.loop_id == target->loop_id
159 && (target->events & PICOEV_READWRITE) != 0) {
160 int revents = ((event->events & EPOLLIN) != 0 ? PICOEV_READ : 0)
161 | ((event->events & EPOLLOUT) != 0 ? PICOEV_WRITE : 0);
162 if (revents != 0) {
163 (*target->callback)(&loop->loop, event->data.fd, revents,
164 target->cb_arg);
165 }
166 } else {
167#if PICOEV_EPOLL_DEFER_DELETES
168 event->events = 0;
169 epoll_ctl(loop->epfd, EPOLL_CTL_DEL, event->data.fd, event);
170#endif
171 }
172 }
173 return 0;
174}
175