struct eph_conn { int sfd; unsigned int events, revents; coroutine_t co; }; int eph_new_conn(int sfd, void *func) { struct eph_conn *conn; struct epoll_event ev; conn = (struct eph_conn *) malloc(sizeof(struct eph_conn)); conn->sfd = sfd; conn->co = co_create(func, conn, NULL, STACKSIZE); ev.events = 0; ev.data.ptr = conn; epoll_ctl(kdpfd, EPOLL_CTL_ADD, sfd, &ev); co_call(conn->co); return 0; } void eph_exit_conn(struct eph_conn *conn) { struct epoll_event ev; epoll_ctl(kdpfd, EPOLL_CTL_DEL, conn->sfd, &ev); co_exit(); } int eph_connect(struct eph_conn *conn, const struct sockaddr *serv_addr, socklen_t addrlen) { if (connect(conn->sfd, serv_addr, addrlen) == -1) { if (errno != EWOULDBLOCK && errno != EINPROGRESS) return -1; co_resume(); if (conn->revents & (EPOLLERR | EPOLLHUP)) return -1; } return 0; } int eph_read(struct eph_conn *conn, void *buf, int nbyte) { int n; while ((n = read(conn->sfd, buf, nbyte)) < 0) { if (errno == EINTR) continue; if (errno != EAGAIN && errno != EWOULDBLOCK) return -1; co_resume(); } return n; } int eph_write(struct eph_conn *conn, void const *buf, int nbyte) { int n; while ((n = write(conn->sfd, buf, nbyte)) < 0) { if (errno == EINTR) continue; if (errno != EAGAIN && errno != EWOULDBLOCK) return -1; co_resume(); } return n; } int eph_accept(struct eph_conn *conn, struct sockaddr *addr, int *addrlen) { int sfd; while ((sfd = accept(conn->sfd, addr, (socklen_t *) addrlen)) < 0) { if (errno == EINTR) continue; if (errno != EAGAIN && errno != EWOULDBLOCK) return -1; co_resume(); } return sfd; } int eph_scheduler(int loop, long timeout) { int i, nfds; struct eph_conn *conn; struct epoll_event *cevents; do { nfds = epoll_wait(kdpfd, events, maxfds, timeout); for (i = 0, cevents = events; i < nfds; i++, cevents++) { conn = cevents->data.ptr; conn->revents = cevents->events; if (conn->revents & conn->events) co_call(conn->co); } } while (loop); return 0; }