📄 pth_high.c
字号:
/* if filedescriptor is still not readable, let thread sleep until it is or the extra event occurs */ if (n == 0) { ev = pth_event(PTH_EVENT_FD|PTH_UNTIL_FD_READABLE|PTH_MODE_STATIC, &ev_key, fd); if (ev_extra != NULL) pth_event_concat(ev, ev_extra, NULL); n = pth_wait(ev); if (ev_extra != NULL) { pth_event_isolate(ev); if (pth_event_status(ev) != PTH_STATUS_OCCURRED) return pth_error(-1, EINTR); } } } /* Now perform the actual read. We're now guarrantied to not block, either because we were already in non-blocking mode or we determined above by polling that the next read(2) call will not block. But keep in mind, that only 1 next read(2) call is guarrantied to not block (except for the EINTR situation). */ while ((n = pth_sc(read)(fd, buf, nbytes)) < 0 && errno == EINTR) ; pth_debug2("pth_read_ev: leave to thread \"%s\"", pth_current->name); return n;}/* Pth variant of write(2) */ssize_t pth_write(int fd, const void *buf, size_t nbytes){ return pth_write_ev(fd, buf, nbytes, NULL);}/* Pth variant of write(2) with extra event(s) */ssize_t pth_write_ev(int fd, const void *buf, size_t nbytes, pth_event_t ev_extra){ struct timeval delay; pth_event_t ev; static pth_key_t ev_key = PTH_KEY_INIT; fd_set fds; int fdmode; ssize_t rv; ssize_t s; int n; pth_implicit_init(); pth_debug2("pth_write_ev: enter from thread \"%s\"", pth_current->name); /* POSIX compliance */ if (nbytes == 0) return 0; if (!pth_util_fd_valid(fd)) return pth_error(-1, EBADF); /* force filedescriptor into non-blocking mode */ if ((fdmode = pth_fdmode(fd, PTH_FDMODE_NONBLOCK)) == PTH_FDMODE_ERROR) return pth_error(-1, EBADF); /* poll filedescriptor if not already in non-blocking operation */ if (fdmode != PTH_FDMODE_NONBLOCK) { /* now directly poll filedescriptor for writeability to avoid unneccessary (and resource consuming because of context switches, etc) event handling through the scheduler */ FD_ZERO(&fds); FD_SET(fd, &fds); delay.tv_sec = 0; delay.tv_usec = 0; while ((n = pth_sc(select)(fd+1, NULL, &fds, NULL, &delay)) < 0 && errno == EINTR) ; if (n < 0 && (errno == EINVAL || errno == EBADF)) return pth_error(-1, errno); rv = 0; for (;;) { /* if filedescriptor is still not writeable, let thread sleep until it is or event occurs */ if (n < 1) { ev = pth_event(PTH_EVENT_FD|PTH_UNTIL_FD_WRITEABLE|PTH_MODE_STATIC, &ev_key, fd); if (ev_extra != NULL) pth_event_concat(ev, ev_extra, NULL); pth_wait(ev); if (ev_extra != NULL) { pth_event_isolate(ev); if (pth_event_status(ev) != PTH_STATUS_OCCURRED) { pth_fdmode(fd, fdmode); return pth_error(-1, EINTR); } } } /* now perform the actual write operation */ while ((s = pth_sc(write)(fd, buf, nbytes)) < 0 && errno == EINTR) ; if (s > 0) rv += s; /* although we're physically now in non-blocking mode, iterate unless all data is written or an error occurs, because we've to mimic the usual blocking I/O behaviour of write(2). */ if (s > 0 && s < (ssize_t)nbytes) { nbytes -= s; buf = (void *)((char *)buf + s); n = 0; continue; } /* pass error to caller, but not for partial writes (rv > 0) */ if (s < 0 && rv == 0) rv = -1; /* stop looping */ break; } } else { /* just perform the actual write operation */ while ((rv = pth_sc(write)(fd, buf, nbytes)) < 0 && errno == EINTR) ; } /* restore filedescriptor mode */ pth_shield { pth_fdmode(fd, fdmode); } pth_debug2("pth_write_ev: leave to thread \"%s\"", pth_current->name); return rv;}/* Pth variant of readv(2) */ssize_t pth_readv(int fd, const struct iovec *iov, int iovcnt){ return pth_readv_ev(fd, iov, iovcnt, NULL);}/* Pth variant of readv(2) with extra event(s) */ssize_t pth_readv_ev(int fd, const struct iovec *iov, int iovcnt, pth_event_t ev_extra){ struct timeval delay; pth_event_t ev; static pth_key_t ev_key = PTH_KEY_INIT; fd_set fds; int fdmode; int n; pth_implicit_init(); pth_debug2("pth_readv_ev: enter from thread \"%s\"", pth_current->name); /* POSIX compliance */ if (iovcnt <= 0 || iovcnt > UIO_MAXIOV) return pth_error(-1, EINVAL); if (!pth_util_fd_valid(fd)) return pth_error(-1, EBADF); /* check mode of filedescriptor */ if ((fdmode = pth_fdmode(fd, PTH_FDMODE_POLL)) == PTH_FDMODE_ERROR) return pth_error(-1, EBADF); /* poll filedescriptor if not already in non-blocking operation */ if (fdmode == PTH_FDMODE_BLOCK) { /* first directly poll filedescriptor for readability to avoid unneccessary (and resource consuming because of context switches, etc) event handling through the scheduler */ FD_ZERO(&fds); FD_SET(fd, &fds); delay.tv_sec = 0; delay.tv_usec = 0; while ((n = pth_sc(select)(fd+1, &fds, NULL, NULL, &delay)) < 0 && errno == EINTR) ; /* if filedescriptor is still not readable, let thread sleep until it is or event occurs */ if (n < 1) { ev = pth_event(PTH_EVENT_FD|PTH_UNTIL_FD_READABLE|PTH_MODE_STATIC, &ev_key, fd); if (ev_extra != NULL) pth_event_concat(ev, ev_extra, NULL); n = pth_wait(ev); if (ev_extra != NULL) { pth_event_isolate(ev); if (pth_event_status(ev) != PTH_STATUS_OCCURRED) return pth_error(-1, EINTR); } } } /* Now perform the actual read. We're now guarrantied to not block, either because we were already in non-blocking mode or we determined above by polling that the next read(2) call will not block. But keep in mind, that only 1 next read(2) call is guarrantied to not block (except for the EINTR situation). */#if PTH_FAKE_RWV while ((n = pth_readv_faked(fd, iov, iovcnt)) < 0 && errno == EINTR) ;#else while ((n = pth_sc(readv)(fd, iov, iovcnt)) < 0 && errno == EINTR) ;#endif pth_debug2("pth_readv_ev: leave to thread \"%s\"", pth_current->name); return n;}/* A faked version of readv(2) */intern ssize_t pth_readv_faked(int fd, const struct iovec *iov, int iovcnt){ char *buffer; size_t bytes, copy, rv; int i; /* determine total number of bytes to read */ bytes = 0; for (i = 0; i < iovcnt; i++) { if (iov[i].iov_len <= 0) return pth_error((ssize_t)(-1), EINVAL); bytes += iov[i].iov_len; } if (bytes <= 0) return pth_error((ssize_t)(-1), EINVAL); /* allocate a temporary buffer */ if ((buffer = (char *)malloc(bytes)) == NULL) return (ssize_t)(-1); /* read data into temporary buffer (caller guarrantied us to not block) */ rv = pth_sc(read)(fd, buffer, bytes); /* scatter read data into callers vector */ if (rv > 0) { bytes = rv; for (i = 0; i < iovcnt; i++) { copy = pth_util_min(iov[i].iov_len, bytes); memcpy(iov[i].iov_base, buffer, copy); buffer += copy; bytes -= copy; if (bytes <= 0) break; } } /* remove the temporary buffer */ pth_shield { free(buffer); } /* return number of read bytes */ return(rv);}/* Pth variant of writev(2) */ssize_t pth_writev(int fd, const struct iovec *iov, int iovcnt){ return pth_writev_ev(fd, iov, iovcnt, NULL);}/* Pth variant of writev(2) with extra event(s) */ssize_t pth_writev_ev(int fd, const struct iovec *iov, int iovcnt, pth_event_t ev_extra){ struct timeval delay; pth_event_t ev; static pth_key_t ev_key = PTH_KEY_INIT; fd_set fds; int fdmode; struct iovec *liov; int liovcnt; size_t nbytes; ssize_t rv; ssize_t s; int n; struct iovec tiov_stack[32]; struct iovec *tiov; int tiovcnt; pth_implicit_init(); pth_debug2("pth_writev_ev: enter from thread \"%s\"", pth_current->name); /* POSIX compliance */ if (iovcnt <= 0 || iovcnt > UIO_MAXIOV) return pth_error(-1, EINVAL); if (!pth_util_fd_valid(fd)) return pth_error(-1, EBADF); /* force filedescriptor into non-blocking mode */ if ((fdmode = pth_fdmode(fd, PTH_FDMODE_NONBLOCK)) == PTH_FDMODE_ERROR) return pth_error(-1, EBADF); /* poll filedescriptor if not already in non-blocking operation */ if (fdmode != PTH_FDMODE_NONBLOCK) { /* provide temporary iovec structure */ if (iovcnt > sizeof(tiov_stack)) { tiovcnt = (sizeof(struct iovec) * UIO_MAXIOV); if ((tiov = (struct iovec *)malloc(tiovcnt)) == NULL) return pth_error(-1, errno); } else { tiovcnt = sizeof(tiov_stack); tiov = tiov_stack; } /* init return value and number of bytes to write */ rv = 0; nbytes = pth_writev_iov_bytes(iov, iovcnt); /* init local iovec structure */ liov = NULL; liovcnt = 0; pth_writev_iov_advance(iov, iovcnt, 0, &liov, &liovcnt, tiov, tiovcnt); /* first directly poll filedescriptor for writeability to avoid unneccessary (and resource consuming because of context switches, etc) event handling through the scheduler */ FD_ZERO(&fds); FD_SET(fd, &fds); delay.tv_sec = 0; delay.tv_usec = 0; while ((n = pth_sc(select)(fd+1, NULL, &fds, NULL, &delay)) < 0 && errno == EINTR) ; for (;;) { /* if filedescriptor is still not writeable, let thread sleep until it is or event occurs */ if (n < 1) { ev = pth_event(PTH_EVENT_FD|PTH_UNTIL_FD_WRITEABLE|PTH_MODE_STATIC, &ev_key, fd); if (ev_extra != NULL) pth_event_concat(ev, ev_extra, NULL); pth_wait(ev); if (ev_extra != NULL) { pth_event_isolate(ev); if (pth_event_status(ev) != PTH_STATUS_OCCURRED) { pth_fdmode(fd, fdmode); if (iovcnt > sizeof(tiov_stack)) free(tiov); return pth_error(-1, EINTR); } } } /* now perform the actual write operation */#if PTH_FAKE_RWV while ((s = pth_writev_faked(fd, liov, liovcnt)) < 0 && errno == EINTR) ;#else while ((s = pth_sc(writev)(fd, liov, liovcnt)) < 0 && errno == EINTR) ;#endif if (s > 0) rv += s; /* although we're physically now in non-blocking mode, iterate unless all data is written or an error occurs, because we've to mimic the usual blocking I/O behaviour of writev(2) */ if (s > 0 && s < (ssize_t)nbytes) { nbytes -= s; pth_writev_iov_advance(iov, iovcnt, s, &liov, &liovcnt, tiov, tiovcnt); n = 0; continue; } /* pass error to caller, but not for partial writes (rv > 0) */ if (s < 0 && rv == 0) rv = -1; /* stop looping */ break; } /* cleanup */ if (iovcnt > sizeof(tiov_stack)) free(tiov); } else { /* just perform the actual write operation */#if PTH_FAKE_RWV while ((rv = pth_writev_faked(fd, iov, iovcnt)) < 0 && errno == EINTR) ;#else while ((rv = pth_sc(writev)(fd, iov, iovcnt)) < 0
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -