netpoll_kqueue.c 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119
  1. // Copyright 2013 The Go Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style
  3. // license that can be found in the LICENSE file.
  4. // +build darwin dragonfly freebsd netbsd openbsd
  5. #include "runtime.h"
  6. #include "defs.h"
  7. #include "malloc.h"
  8. // Integrated network poller (kqueue-based implementation).
  9. int32 runtime_kqueue(void);
  10. int32 runtime_kevent(int32, Kevent*, int32, Kevent*, int32, Timespec*);
  11. void runtime_closeonexec(int32);
  12. static int32 kq = -1;
  13. void
  14. runtime_netpollinit(void)
  15. {
  16. kq = runtime_kqueue();
  17. if(kq < 0) {
  18. runtime_printf("netpollinit: kqueue failed with %d\n", -kq);
  19. runtime_throw("netpollinit: kqueue failed");
  20. }
  21. runtime_closeonexec(kq);
  22. }
  23. int32
  24. runtime_netpollopen(uintptr fd, PollDesc *pd)
  25. {
  26. Kevent ev[2];
  27. int32 n;
  28. // Arm both EVFILT_READ and EVFILT_WRITE in edge-triggered mode (EV_CLEAR)
  29. // for the whole fd lifetime. The notifications are automatically unregistered
  30. // when fd is closed.
  31. ev[0].ident = (uint32)fd;
  32. ev[0].filter = EVFILT_READ;
  33. ev[0].flags = EV_ADD|EV_CLEAR;
  34. ev[0].fflags = 0;
  35. ev[0].data = 0;
  36. ev[0].udata = (kevent_udata)pd;
  37. ev[1] = ev[0];
  38. ev[1].filter = EVFILT_WRITE;
  39. n = runtime_kevent(kq, ev, 2, nil, 0, nil);
  40. if(n < 0)
  41. return -n;
  42. return 0;
  43. }
  44. int32
  45. runtime_netpollclose(uintptr fd)
  46. {
  47. // Don't need to unregister because calling close()
  48. // on fd will remove any kevents that reference the descriptor.
  49. USED(fd);
  50. return 0;
  51. }
  52. void
  53. runtime_netpollarm(PollDesc* pd, int32 mode)
  54. {
  55. USED(pd, mode);
  56. runtime_throw("unused");
  57. }
  58. // Polls for ready network connections.
  59. // Returns list of goroutines that become runnable.
  60. G*
  61. runtime_netpoll(bool block)
  62. {
  63. static int32 lasterr;
  64. Kevent events[64], *ev;
  65. Timespec ts, *tp;
  66. int32 n, i, mode;
  67. G *gp;
  68. if(kq == -1)
  69. return nil;
  70. tp = nil;
  71. if(!block) {
  72. ts.tv_sec = 0;
  73. ts.tv_nsec = 0;
  74. tp = &ts;
  75. }
  76. gp = nil;
  77. retry:
  78. n = runtime_kevent(kq, nil, 0, events, nelem(events), tp);
  79. if(n < 0) {
  80. if(n != -EINTR && n != lasterr) {
  81. lasterr = n;
  82. runtime_printf("runtime: kevent on fd %d failed with %d\n", kq, -n);
  83. }
  84. goto retry;
  85. }
  86. for(i = 0; i < n; i++) {
  87. ev = &events[i];
  88. mode = 0;
  89. if(ev->filter == EVFILT_READ)
  90. mode += 'r';
  91. if(ev->filter == EVFILT_WRITE)
  92. mode += 'w';
  93. if(mode)
  94. runtime_netpollready(&gp, (PollDesc*)ev->udata, mode);
  95. }
  96. if(block && gp == nil)
  97. goto retry;
  98. return gp;
  99. }
  100. void
  101. runtime_netpoll_scan(struct Workbuf** wbufp, void (*enqueue1)(struct Workbuf**, Obj))
  102. {
  103. USED(wbufp);
  104. USED(enqueue1);
  105. }