| 276 | } |
| 277 | |
| 278 | int fd_close(int fd) { |
| 279 | if (fd < 0) { |
| 280 | // what close(-1) returns |
| 281 | errno = EBADF; |
| 282 | return -1; |
| 283 | } |
| 284 | butil::atomic<EpollButex*>* pbutex = bthread::fd_butexes.get(fd); |
| 285 | if (NULL == pbutex) { |
| 286 | // Did not call bthread_fd functions, close directly. |
| 287 | return close(fd); |
| 288 | } |
| 289 | EpollButex* butex = pbutex->exchange( |
| 290 | CLOSING_GUARD, butil::memory_order_relaxed); |
| 291 | if (butex == CLOSING_GUARD) { |
| 292 | // concurrent double close detected. |
| 293 | errno = EBADF; |
| 294 | return -1; |
| 295 | } |
| 296 | if (butex != NULL) { |
| 297 | butex->fetch_add(1, butil::memory_order_relaxed); |
| 298 | butex_wake_all(butex); |
| 299 | } |
| 300 | #if defined(OS_LINUX) |
| 301 | epoll_ctl(_epfd, EPOLL_CTL_DEL, fd, NULL); |
| 302 | #elif defined(OS_MACOSX) |
| 303 | struct kevent evt; |
| 304 | EV_SET(&evt, fd, EVFILT_WRITE, EV_DELETE, 0, 0, NULL); |
| 305 | kevent(_epfd, &evt, 1, NULL, 0, NULL); |
| 306 | EV_SET(&evt, fd, EVFILT_READ, EV_DELETE, 0, 0, NULL); |
| 307 | kevent(_epfd, &evt, 1, NULL, 0, NULL); |
| 308 | #endif |
| 309 | const int rc = close(fd); |
| 310 | pbutex->exchange(butex, butil::memory_order_relaxed); |
| 311 | return rc; |
| 312 | } |
| 313 | |
| 314 | bool started() const { |
| 315 | return _epfd >= 0; |
nothing calls this directly
no test coverage detected