LEFT | RIGHT |
1 // Copyright 2012 The Go Authors. All rights reserved. | 1 // Copyright 2012 The Go Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style | 2 // Use of this source code is governed by a BSD-style |
3 // license that can be found in the LICENSE file. | 3 // license that can be found in the LICENSE file. |
4 | 4 |
5 #include "runtime.h" | 5 #include "runtime.h" |
6 #include "arch_GOARCH.h" | 6 #include "arch_GOARCH.h" |
7 #include "defs_GOOS_GOARCH.h" | 7 #include "defs_GOOS_GOARCH.h" |
8 #include "malloc.h" | 8 #include "malloc.h" |
9 | 9 |
10 #define LOG if(1) {} else runtime·printf | 10 #define LOG if(1) {} else runtime·printf |
(...skipping 14 matching lines...) Expand all Loading... |
25 int64 wd; | 25 int64 wd; |
26 }; | 26 }; |
27 | 27 |
28 static struct | 28 static struct |
29 { | 29 { |
30 Lock; | 30 Lock; |
31 int32 fd; | 31 int32 fd; |
32 PollFD* cache; | 32 PollFD* cache; |
33 } s; | 33 } s; |
34 | 34 |
35 static void epollblock(PollFD *fd, G**); | 35 static void» epollblock(PollFD *fd, G**); |
36 static G* epollunblock(PollFD *fd, G**); | 36 static G*» epollunblock(PollFD *fd, G**); |
37 static void deadline(int64, Eface); | 37 static void» deadline(int64, Eface); |
38 static void readDeadline(int64, Eface); | 38 static void» readDeadline(int64, Eface); |
39 static void writeDeadline(int64, Eface); | 39 static void» writeDeadline(int64, Eface); |
| 40 static PollFD*» allocFD(void); |
| 41 static void» pollloop(void); |
40 | 42 |
41 #define READY ((G*)1) | 43 #define READY ((G*)1) |
42 | 44 |
43 void | 45 void |
44 net·runtime_initPollServer(void) | 46 net·runtime_initPollServer(void) |
45 { | 47 { |
46 int32 errno; | 48 int32 errno; |
47 | 49 |
48 LOG("init epoll dispatcher\n"); | 50 LOG("init epoll dispatcher\n"); |
| 51 runtime·newproc1((byte*)pollloop, nil, 0, 0, net·runtime_initPollServer)
; |
49 errno = runtime·epollcreate1(EPOLL_CLOEXEC, &s.fd); | 52 errno = runtime·epollcreate1(EPOLL_CLOEXEC, &s.fd); |
50 LOG("epollcreate1: errno=%d fd=%d\n", errno, s.fd); | 53 LOG("epollcreate1: errno=%d fd=%d\n", errno, s.fd); |
51 if(errno == 0) | 54 if(errno == 0) |
52 return; | 55 return; |
53 errno = runtime·epollcreate(1024, &s.fd); | 56 errno = runtime·epollcreate(1024, &s.fd); |
54 LOG("epollcreate: errno=%d fd=%d\n", errno, s.fd); | 57 LOG("epollcreate: errno=%d fd=%d\n", errno, s.fd); |
55 if(errno == 0) | 58 if(errno == 0) |
56 // TODO(dvyukov): set CLOEXEC | 59 // TODO(dvyukov): set CLOEXEC |
57 return; | 60 return; |
58 runtime·printf("epoll: failed to create descriptor (%d)\n", errno); | 61 runtime·printf("epoll: failed to create descriptor (%d)\n", errno); |
59 runtime·throw("epoll: failed to create descriptor"); | 62 runtime·throw("epoll: failed to create descriptor"); |
60 } | 63 } |
61 | 64 |
62 void | 65 void |
63 net·runtime_initFD(int32 intfd, PollFD *fd, Eface err) | 66 net·runtime_initFD(int32 intfd, PollFD *fd, Eface err) |
64 { | 67 { |
65 EpollEvent ev; | 68 EpollEvent ev; |
66 | 69 |
67 » fd = nil; | 70 » fd = allocFD(); |
68 » runtime·lock(&s); | 71 » runtime·lock(fd); |
69 » if(s.cache != nil) { | 72 » if(fd->wg != nil && fd->wg != READY) |
70 » » fd = s.cache; | 73 » » runtime·throw("epoll: blocked write on free descriptor"); |
71 » » s.cache = fd->link; | 74 » if(fd->rg != nil && fd->rg != READY) |
72 » } | 75 » » runtime·throw("epoll: blocked read on free descriptor"); |
73 » runtime·unlock(&s); | 76 » fd->closing = false; |
74 » if(fd != nil) { | 77 » fd->seq++; |
75 » » runtime·lock(fd); | 78 » fd->rg = nil; |
76 » » if(fd->wg != nil && fd->wg != READY) | 79 » fd->rd = 0; |
77 » » » runtime·throw("epoll: blocked write on free descriptor")
; | 80 » fd->wg = nil; |
78 » » if(fd->rg != nil && fd->rg != READY) | 81 » fd->wd = 0; |
79 » » » runtime·throw("epoll: blocked read on free descriptor"); | 82 » runtime·unlock(fd); |
80 » » fd->closing = false; | |
81 » » fd->seq++; | |
82 » » fd->rg = nil; | |
83 » » fd->rd = 0; | |
84 » » fd->wg = nil; | |
85 » » fd->wd = 0; | |
86 » » runtime·unlock(fd); | |
87 » } else { | |
88 » » // TODO(dvyukov): batch allocation | |
89 » » fd = (PollFD*)runtime·SysAlloc(sizeof(*fd)); | |
90 » } | |
91 ev.events = EPOLLIN|EPOLLOUT|EPOLLRDHUP|EPOLLET; | 83 ev.events = EPOLLIN|EPOLLOUT|EPOLLRDHUP|EPOLLET; |
92 ev.ctx = fd; | 84 ev.ctx = fd; |
93 runtime·epollctl(s.fd, EPOLL_CTL_ADD, intfd, &ev); | 85 runtime·epollctl(s.fd, EPOLL_CTL_ADD, intfd, &ev); |
94 // TODO(dvyukov): handle errors | 86 // TODO(dvyukov): handle errors |
95 err.type = nil; | 87 err.type = nil; |
96 err.data = nil; | 88 err.data = nil; |
97 FLUSH(&err); | 89 FLUSH(&err); |
98 FLUSH(&fd); | 90 FLUSH(&fd); |
99 LOG("init fd %d with desc %p\n", intfd, fd); | 91 LOG("init fd %d with desc %p\n", intfd, fd); |
100 } | 92 } |
(...skipping 121 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
222 runtime·deltimer(&fd->wt); | 214 runtime·deltimer(&fd->wt); |
223 fd->wt.f = nil; | 215 fd->wt.f = nil; |
224 } | 216 } |
225 runtime·unlock(fd); | 217 runtime·unlock(fd); |
226 if(rg) | 218 if(rg) |
227 runtime·ready(rg); | 219 runtime·ready(rg); |
228 if(wg) | 220 if(wg) |
229 runtime·ready(wg); | 221 runtime·ready(wg); |
230 } | 222 } |
231 | 223 |
232 G* | 224 static G* |
233 runtime·netwait(uint32 ms) | 225 netwait(uint32 ms, uint32 cnt) |
234 { | 226 { |
235 EpollEvent ev, events[128]; | 227 EpollEvent ev, events[128]; |
236 PollFD *fd; | 228 PollFD *fd; |
237 G *gp, *rg, *wg; | 229 G *gp, *rg, *wg; |
238 int32 n, i; | 230 int32 n, i; |
239 | 231 |
240 LOG("epoll wait\n"); | 232 LOG("epoll wait\n"); |
| 233 /* |
241 if(s.fd == 0) { | 234 if(s.fd == 0) { |
242 runtime·usleep(ms*1000); | 235 runtime·usleep(ms*1000); |
243 return nil; | 236 return nil; |
244 } | 237 } |
245 » n = runtime·epollwait(s.fd, events, nelem(events), ms); | 238 » */ |
| 239 » if(cnt > nelem(events)) |
| 240 » » cnt = nelem(events); |
| 241 » runtime·entersyscall(); |
| 242 » n = runtime·epollwait(s.fd, events, cnt, ms); |
| 243 » runtime·exitsyscall(); |
246 //TODO(dvyukov): handle errors other than EAGAIN and EINTR | 244 //TODO(dvyukov): handle errors other than EAGAIN and EINTR |
247 LOG("epoll wait got %d\n", n); | 245 LOG("epoll wait got %d\n", n); |
248 if(n <= 0) | 246 if(n <= 0) |
249 return nil; | 247 return nil; |
250 gp = nil; | 248 gp = nil; |
251 for(i = 0; i < n; i++) { | 249 for(i = 0; i < n; i++) { |
252 ev = events[i]; | 250 ev = events[i]; |
253 if(ev.events == 0) | 251 if(ev.events == 0) |
254 continue; | 252 continue; |
255 fd = (PollFD*)ev.ctx; | 253 fd = (PollFD*)ev.ctx; |
(...skipping 11 matching lines...) Expand all Loading... |
267 } | 265 } |
268 if(wg) { | 266 if(wg) { |
269 wg->schedlink = gp; | 267 wg->schedlink = gp; |
270 gp = wg; | 268 gp = wg; |
271 } | 269 } |
272 } | 270 } |
273 return gp; | 271 return gp; |
274 } | 272 } |
275 | 273 |
276 static void | 274 static void |
| 275 pollloop(void) |
| 276 { |
| 277 G *gp, *gp1; |
| 278 |
| 279 for(;;) { |
| 280 gp = netwait(10, 10); |
| 281 while(gp) { |
| 282 gp1 = gp; |
| 283 gp = gp->schedlink; |
| 284 runtime·ready(gp1); |
| 285 } |
| 286 } |
| 287 } |
| 288 |
| 289 static void |
277 epollblock(PollFD *fd, G **gp) | 290 epollblock(PollFD *fd, G **gp) |
278 { | 291 { |
279 LOG("epoll block %p on %p\n", g, gp); | 292 LOG("epoll block %p on %p\n", g, gp); |
280 if(*gp == READY) { | 293 if(*gp == READY) { |
281 *gp = nil; | 294 *gp = nil; |
282 return; | 295 return; |
283 } | 296 } |
284 if(*gp != nil) | 297 if(*gp != nil) |
285 runtime·throw("epoll: double wait"); | 298 runtime·throw("epoll: double wait"); |
286 *gp = g; | 299 *gp = g; |
287 » runtime·park(&fd->Lock, (void(*)(void*))runtime·unlock, "IO wait"); | 300 » runtime·park(runtime·unlock, &fd->Lock, "IO wait"); |
288 runtime·lock(fd); | 301 runtime·lock(fd); |
289 } | 302 } |
290 | 303 |
291 static G* | 304 static G* |
292 epollunblock(PollFD *fd, G **gp) | 305 epollunblock(PollFD *fd, G **gp) |
293 { | 306 { |
294 G *old; | 307 G *old; |
295 | 308 |
296 USED(fd); | 309 USED(fd); |
297 LOG("epoll unblock on %p\n", gp); | 310 LOG("epoll unblock on %p\n", gp); |
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
355 { | 368 { |
356 deadlineimpl(now, arg, true, false); | 369 deadlineimpl(now, arg, true, false); |
357 } | 370 } |
358 | 371 |
359 static void | 372 static void |
360 writeDeadline(int64 now, Eface arg) | 373 writeDeadline(int64 now, Eface arg) |
361 { | 374 { |
362 deadlineimpl(now, arg, false, true); | 375 deadlineimpl(now, arg, false, true); |
363 } | 376 } |
364 | 377 |
| 378 static PollFD* |
| 379 allocFD(void) |
| 380 { |
| 381 PollFD *fd; |
| 382 uint32 i, n; |
| 383 |
| 384 runtime·lock(&s); |
| 385 if(s.cache == nil) { |
| 386 n = PageSize/sizeof(*fd); |
| 387 if(n == 0) |
| 388 n = 1; |
| 389 fd = (PollFD*)runtime·SysAlloc(n*sizeof(*fd)); |
| 390 for(i=0; i<n; i++) { |
| 391 fd[i].link = s.cache; |
| 392 s.cache = &fd[i]; |
| 393 }· |
| 394 } |
| 395 fd = s.cache; |
| 396 s.cache = fd->link; |
| 397 runtime·unlock(&s); |
| 398 return fd; |
| 399 } |
LEFT | RIGHT |