Skip to content

Commit 63e3b81

Browse files
committed
refactor internal AE api, avoiding eventLoop
Signed-off-by: Jim Brunner <brunnerj@amazon.com>
1 parent 3f0d910 commit 63e3b81

6 files changed

Lines changed: 121 additions & 124 deletions

File tree

src/ae.c

Lines changed: 18 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,10 @@
7373
assert(pthread_mutex_unlock(&(eventLoop)->poll_mutex) == 0); \
7474
}
7575

76+
/* Regardless of the flags used in AE, the only flags understood by the backend
77+
* implementations are AE_READABLE & AE_WRITABLE. */
78+
#define BACKEND_MASK(mask) ((mask) & (AE_READABLE | AE_WRITABLE))
79+
7680
aeEventLoop *aeCreateEventLoop(int setsize) {
7781
aeEventLoop *eventLoop;
7882
int i;
@@ -98,7 +102,7 @@ aeEventLoop *aeCreateEventLoop(int setsize) {
98102
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK);
99103
if (pthread_mutex_init(&eventLoop->poll_mutex, &attr) != 0) goto err;
100104

101-
if (aeApiCreate(eventLoop) == -1) goto err;
105+
if ((eventLoop->apidata = aeApiCreate(setsize)) == NULL) goto err;
102106
/* Events with mask == AE_NONE are not set. So let's initialize the
103107
* vector with it. */
104108
for (i = 0; i < setsize; i++) eventLoop->events[i].mask = AE_NONE;
@@ -144,7 +148,7 @@ int aeResizeSetSize(aeEventLoop *eventLoop, int setsize) {
144148

145149
if (setsize == eventLoop->setsize) goto done;
146150
if (eventLoop->maxfd >= setsize) goto err;
147-
if (aeApiResize(eventLoop, setsize) == -1) goto err;
151+
if (aeApiResize(eventLoop->apidata, setsize) == -1) goto err;
148152

149153
eventLoop->events = zrealloc(eventLoop->events, sizeof(aeFileEvent) * setsize);
150154
eventLoop->fired = zrealloc(eventLoop->fired, sizeof(aeFiredEvent) * setsize);
@@ -163,7 +167,7 @@ int aeResizeSetSize(aeEventLoop *eventLoop, int setsize) {
163167
}
164168

165169
void aeDeleteEventLoop(aeEventLoop *eventLoop) {
166-
aeApiFree(eventLoop);
170+
aeApiFree(eventLoop->apidata);
167171
zfree(eventLoop->events);
168172
zfree(eventLoop->fired);
169173

@@ -192,7 +196,10 @@ int aeCreateFileEvent(aeEventLoop *eventLoop, int fd, int mask, aeFileProc *proc
192196
}
193197
aeFileEvent *fe = &eventLoop->events[fd];
194198

195-
if (aeApiAddEvent(eventLoop, fd, mask) == -1) goto done;
199+
int backend_add_mask = BACKEND_MASK(mask) & ~fe->mask; // just the meaningful additions
200+
if (backend_add_mask) {
201+
if (aeApiAddEvent(eventLoop->apidata, fd, BACKEND_MASK(fe->mask), backend_add_mask) == -1) goto done;
202+
}
196203
fe->mask |= mask;
197204
if (mask & AE_READABLE) fe->rfileProc = proc;
198205
if (mask & AE_WRITABLE) fe->wfileProc = proc;
@@ -220,7 +227,8 @@ void aeDeleteFileEvent(aeEventLoop *eventLoop, int fd, int mask) {
220227
/* Only remove attached events */
221228
mask = mask & fe->mask;
222229

223-
fe->mask = fe->mask & (~mask);
230+
int old_mask = fe->mask;
231+
fe->mask = fe->mask & ~mask;
224232
if (fd == eventLoop->maxfd && fe->mask == AE_NONE) {
225233
/* Update the max fd */
226234
int j;
@@ -233,10 +241,9 @@ void aeDeleteFileEvent(aeEventLoop *eventLoop, int fd, int mask) {
233241
/* Check whether there are events to be removed.
234242
* Note: user may remove the AE_BARRIER without
235243
* touching the actual events. */
236-
if (mask & (AE_READABLE | AE_WRITABLE)) {
237-
/* Must be invoked after the eventLoop mask is modified,
238-
* which is required by evport and epoll */
239-
aeApiDelEvent(eventLoop, fd, mask);
244+
int backend_del_mask = BACKEND_MASK(mask); // just the meaningful deletions
245+
if (backend_del_mask) {
246+
aeApiDelEvent(eventLoop->apidata, fd, BACKEND_MASK(old_mask), backend_del_mask);
240247
}
241248

242249
done:
@@ -390,7 +397,7 @@ static int processTimeEvents(aeEventLoop *eventLoop) {
390397
int aePoll(aeEventLoop *eventLoop, struct timeval *tvp) {
391398
AE_LOCK(eventLoop);
392399

393-
int ret = aeApiPoll(eventLoop, tvp);
400+
int ret = aeApiPoll(eventLoop->apidata, eventLoop->fired, eventLoop->events, eventLoop->setsize, eventLoop->maxfd, tvp);
394401

395402
AE_UNLOCK(eventLoop);
396403
return ret;
@@ -449,7 +456,7 @@ int aeProcessEvents(aeEventLoop *eventLoop, int flags) {
449456
}
450457
/* Call the multiplexing API, will return only on timeout or when
451458
* some event fires. */
452-
numevents = aeApiPoll(eventLoop, tvp);
459+
numevents = aeApiPoll(eventLoop->apidata, eventLoop->fired, eventLoop->events, eventLoop->setsize, eventLoop->maxfd, tvp);
453460
}
454461

455462
/* Don't process file events if not requested. */

src/ae.h

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,14 @@
6565
struct timeval; /* forward declaration */
6666
struct aeEventLoop;
6767

68+
/* Opaque per-backend polling state (epoll/kqueue/evport/select).
69+
*
70+
* The concrete struct aeApiState is defined privately by each polling backend
71+
* and its layout varies between them. ae.c only ever holds and passes a typed
72+
* pointer to it, so the forward declaration here lets the event loop and the
73+
* inner aeApi* interface use "aeApiState *" instead of an untyped "void *". */
74+
typedef struct aeApiState aeApiState;
75+
6876
/* Types and data structures */
6977
typedef void aeFileProc(struct aeEventLoop *eventLoop, int fd, void *clientData, int mask);
7078
typedef long long aeTimeProc(struct aeEventLoop *eventLoop, long long id, void *clientData);
@@ -109,7 +117,7 @@ typedef struct aeEventLoop {
109117
aeFiredEvent *fired; /* Fired events */
110118
aeTimeEvent *timeEventHead;
111119
int stop;
112-
void *apidata; /* This is used for polling API specific data */
120+
aeApiState *apidata; /* Polling API specific state (owned by the backend) */
113121
aeBeforeSleepProc *beforesleep;
114122
aeAfterSleepProc *aftersleep;
115123
aeCustomPollProc *custompoll;

src/ae_epoll.c

Lines changed: 19 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -36,63 +36,55 @@ typedef struct aeApiState {
3636
struct epoll_event *events;
3737
} aeApiState;
3838

39-
static int aeApiCreate(aeEventLoop *eventLoop) {
39+
static aeApiState *aeApiCreate(int setsize) {
4040
aeApiState *state = zmalloc(sizeof(aeApiState));
4141

42-
if (!state) return -1;
43-
state->events = zmalloc(sizeof(struct epoll_event) * eventLoop->setsize);
42+
if (!state) return NULL;
43+
state->events = zmalloc(sizeof(struct epoll_event) * setsize);
4444
if (!state->events) {
4545
zfree(state);
46-
return -1;
46+
return NULL;
4747
}
4848
state->epfd = epoll_create(1024); /* 1024 is just a hint for the kernel */
4949
if (state->epfd == -1) {
5050
zfree(state->events);
5151
zfree(state);
52-
return -1;
52+
return NULL;
5353
}
5454
anetCloexec(state->epfd);
55-
eventLoop->apidata = state;
56-
return 0;
55+
return state;
5756
}
5857

59-
static int aeApiResize(aeEventLoop *eventLoop, int setsize) {
60-
aeApiState *state = eventLoop->apidata;
61-
58+
static int aeApiResize(aeApiState *state, int setsize) {
6259
state->events = zrealloc(state->events, sizeof(struct epoll_event) * setsize);
6360
return 0;
6461
}
6562

66-
static void aeApiFree(aeEventLoop *eventLoop) {
67-
aeApiState *state = eventLoop->apidata;
68-
63+
static void aeApiFree(aeApiState *state) {
6964
close(state->epfd);
7065
zfree(state->events);
7166
zfree(state);
7267
}
7368

74-
static int aeApiAddEvent(aeEventLoop *eventLoop, int fd, int mask) {
75-
aeApiState *state = eventLoop->apidata;
69+
static int aeApiAddEvent(aeApiState *state, int fd, int curr_mask, int add_mask) {
7670
struct epoll_event ee = {0}; /* avoid valgrind warning */
7771
/* If the fd was already monitored for some event, we need a MOD
7872
* operation. Otherwise, we need an ADD operation. */
79-
int op = eventLoop->events[fd].mask == AE_NONE ? EPOLL_CTL_ADD : EPOLL_CTL_MOD;
73+
int op = (curr_mask & (AE_READABLE | AE_WRITABLE)) ? EPOLL_CTL_MOD : EPOLL_CTL_ADD;
8074

8175
ee.events = 0;
82-
mask |= eventLoop->events[fd].mask; /* Merge old events */
76+
int mask = curr_mask | add_mask;
8377
if (mask & AE_READABLE) ee.events |= EPOLLIN;
8478
if (mask & AE_WRITABLE) ee.events |= EPOLLOUT;
8579
ee.data.fd = fd;
8680
if (epoll_ctl(state->epfd, op, fd, &ee) == -1) return -1;
8781
return 0;
8882
}
8983

90-
static void aeApiDelEvent(aeEventLoop *eventLoop, int fd, int mask) {
91-
aeApiState *state = eventLoop->apidata;
84+
static void aeApiDelEvent(aeApiState *state, int fd, int curr_mask, int del_mask) {
9285
struct epoll_event ee = {0}; /* avoid valgrind warning */
9386

94-
/* We rely on the fact that our caller has already updated the mask in the eventLoop. */
95-
mask = eventLoop->events[fd].mask;
87+
int mask = curr_mask & ~del_mask;
9688

9789
ee.events = 0;
9890
if (mask & AE_READABLE) ee.events |= EPOLLIN;
@@ -107,11 +99,12 @@ static void aeApiDelEvent(aeEventLoop *eventLoop, int fd, int mask) {
10799
}
108100
}
109101

110-
static int aeApiPoll(aeEventLoop *eventLoop, struct timeval *tvp) {
111-
aeApiState *state = eventLoop->apidata;
102+
static int aeApiPoll(aeApiState *state, aeFiredEvent *fired, aeFileEvent *events, int setsize, int maxfd, struct timeval *tvp) {
103+
AE_NOTUSED(events);
104+
AE_NOTUSED(maxfd);
112105
int retval, numevents = 0;
113106

114-
retval = epoll_wait(state->epfd, state->events, eventLoop->setsize,
107+
retval = epoll_wait(state->epfd, state->events, setsize,
115108
tvp ? (tvp->tv_sec * 1000 + (tvp->tv_usec + 999) / 1000) : -1);
116109
if (retval > 0) {
117110
int j;
@@ -125,8 +118,8 @@ static int aeApiPoll(aeEventLoop *eventLoop, struct timeval *tvp) {
125118
if (e->events & EPOLLOUT) mask |= AE_WRITABLE;
126119
if (e->events & EPOLLERR) mask |= AE_WRITABLE | AE_READABLE;
127120
if (e->events & EPOLLHUP) mask |= AE_WRITABLE | AE_READABLE;
128-
eventLoop->fired[j].fd = e->data.fd;
129-
eventLoop->fired[j].mask = mask;
121+
fired[j].fd = e->data.fd;
122+
fired[j].mask = mask;
130123
}
131124
} else if (retval == -1 && errno != EINTR) {
132125
panic("aeApiPoll: epoll_wait, %s", strerror(errno));

src/ae_evport.c

Lines changed: 27 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -71,15 +71,16 @@ typedef struct aeApiState {
7171
int pending_masks[MAX_EVENT_BATCHSZ]; /* pending fds' masks */
7272
} aeApiState;
7373

74-
static int aeApiCreate(aeEventLoop *eventLoop) {
74+
static aeApiState *aeApiCreate(int setsize) {
75+
AE_NOTUSED(setsize);
7576
int i;
7677
aeApiState *state = zmalloc(sizeof(aeApiState));
77-
if (!state) return -1;
78+
if (!state) return NULL;
7879

7980
state->portfd = port_create();
8081
if (state->portfd == -1) {
8182
zfree(state);
82-
return -1;
83+
return NULL;
8384
}
8485
anetCloexec(state->portfd);
8586

@@ -90,20 +91,17 @@ static int aeApiCreate(aeEventLoop *eventLoop) {
9091
state->pending_masks[i] = AE_NONE;
9192
}
9293

93-
eventLoop->apidata = state;
94-
return 0;
94+
return state;
9595
}
9696

97-
static int aeApiResize(aeEventLoop *eventLoop, int setsize) {
98-
(void)eventLoop;
99-
(void)setsize;
97+
static int aeApiResize(aeApiState *state, int setsize) {
98+
AE_NOTUSED(state);
99+
AE_NOTUSED(setsize);
100100
/* Nothing to resize here. */
101101
return 0;
102102
}
103103

104-
static void aeApiFree(aeEventLoop *eventLoop) {
105-
aeApiState *state = eventLoop->apidata;
106-
104+
static void aeApiFree(aeApiState *state) {
107105
close(state->portfd);
108106
zfree(state);
109107
}
@@ -144,19 +142,16 @@ static int aeApiAssociate(const char *where, int portfd, int fd, int mask) {
144142
return rv;
145143
}
146144

147-
static int aeApiAddEvent(aeEventLoop *eventLoop, int fd, int mask) {
148-
aeApiState *state = eventLoop->apidata;
149-
int fullmask, pfd;
150-
151-
if (evport_debug) fprintf(stderr, "aeApiAddEvent: fd %d mask 0x%x\n", fd, mask);
145+
static int aeApiAddEvent(aeApiState *state, int fd, int curr_mask, int add_mask) {
146+
if (evport_debug) fprintf(stderr, "aeApiAddEvent: fd %d mask 0x%x\n", fd, add_mask);
152147

153148
/*
154149
* Since port_associate's "events" argument replaces any existing events, we
155150
* must be sure to include whatever events are already associated when
156151
* we call port_associate() again.
157152
*/
158-
fullmask = mask | eventLoop->events[fd].mask;
159-
pfd = aeApiLookupPending(state, fd);
153+
int mask = curr_mask | add_mask;
154+
int pfd = aeApiLookupPending(state, fd);
160155

161156
if (pfd != -1) {
162157
/*
@@ -166,18 +161,17 @@ static int aeApiAddEvent(aeEventLoop *eventLoop, int fd, int mask) {
166161
* re-associated as usual when aeApiPoll is called again.
167162
*/
168163
if (evport_debug) fprintf(stderr, "aeApiAddEvent: adding to pending fd %d\n", fd);
169-
state->pending_masks[pfd] |= fullmask;
164+
state->pending_masks[pfd] |= mask;
170165
return 0;
171166
}
172167

173-
return (aeApiAssociate("aeApiAddEvent", state->portfd, fd, fullmask));
168+
return (aeApiAssociate("aeApiAddEvent", state->portfd, fd, mask));
174169
}
175170

176-
static void aeApiDelEvent(aeEventLoop *eventLoop, int fd, int mask) {
177-
aeApiState *state = eventLoop->apidata;
171+
static void aeApiDelEvent(aeApiState *state, int fd, int curr_mask, int del_mask) {
178172
int fullmask, pfd;
179173

180-
if (evport_debug) fprintf(stderr, "del fd %d mask 0x%x\n", fd, mask);
174+
if (evport_debug) fprintf(stderr, "del fd %d mask 0x%x\n", fd, del_mask);
181175

182176
pfd = aeApiLookupPending(state, fd);
183177

@@ -189,7 +183,7 @@ static void aeApiDelEvent(aeEventLoop *eventLoop, int fd, int mask) {
189183
* associated with the port. All we need to do is update
190184
* pending_mask appropriately.
191185
*/
192-
state->pending_masks[pfd] &= ~mask;
186+
state->pending_masks[pfd] &= ~del_mask;
193187

194188
if (state->pending_masks[pfd] == AE_NONE) state->pending_fds[pfd] = -1;
195189

@@ -199,13 +193,10 @@ static void aeApiDelEvent(aeEventLoop *eventLoop, int fd, int mask) {
199193
/*
200194
* The fd is currently associated with the port. Like with the add case
201195
* above, we must look at the full mask for the file descriptor before
202-
* updating that association. We don't have a good way of knowing what the
203-
* events are without looking into the eventLoop state directly. We rely on
204-
* the fact that our caller has already updated the mask in the eventLoop.
205196
*/
206197

207-
fullmask = eventLoop->events[fd].mask;
208-
if (fullmask == AE_NONE) {
198+
int mask = curr_mask & ~del_mask;
199+
if (mask == AE_NONE) {
209200
/*
210201
* We're removing *all* events, so use port_dissociate to remove the
211202
* association completely. Failure here indicates a bug.
@@ -216,7 +207,7 @@ static void aeApiDelEvent(aeEventLoop *eventLoop, int fd, int mask) {
216207
perror("aeApiDelEvent: port_dissociate");
217208
abort(); /* will not return */
218209
}
219-
} else if (aeApiAssociate("aeApiDelEvent", state->portfd, fd, fullmask) != 0) {
210+
} else if (aeApiAssociate("aeApiDelEvent", state->portfd, fd, mask) != 0) {
220211
/*
221212
* ENOMEM is a potentially transient condition, but the kernel won't
222213
* generally return it unless things are really bad. EAGAIN indicates
@@ -228,8 +219,10 @@ static void aeApiDelEvent(aeEventLoop *eventLoop, int fd, int mask) {
228219
}
229220
}
230221

231-
static int aeApiPoll(aeEventLoop *eventLoop, struct timeval *tvp) {
232-
aeApiState *state = eventLoop->apidata;
222+
static int aeApiPoll(aeApiState *state, aeFiredEvent *fired, aeFileEvent *events, int setsize, int maxfd, struct timeval *tvp) {
223+
AE_NOTUSED(events);
224+
AE_NOTUSED(setsize);
225+
AE_NOTUSED(maxfd);
233226
struct timespec timeout, *tsp;
234227
uint_t mask, i;
235228
uint_t nevents;
@@ -282,8 +275,8 @@ static int aeApiPoll(aeEventLoop *eventLoop, struct timeval *tvp) {
282275
if (event[i].portev_events & POLLIN) mask |= AE_READABLE;
283276
if (event[i].portev_events & POLLOUT) mask |= AE_WRITABLE;
284277

285-
eventLoop->fired[i].fd = event[i].portev_object;
286-
eventLoop->fired[i].mask = mask;
278+
fired[i].fd = event[i].portev_object;
279+
fired[i].mask = mask;
287280

288281
if (evport_debug) fprintf(stderr, "aeApiPoll: fd %d mask 0x%x\n", (int)event[i].portev_object, mask);
289282

0 commit comments

Comments
 (0)