int acl_timed_connect(ACL_SOCKET sock, const struct sockaddr * sa, socklen_t len, int timeout) { int err; /* * Sanity check. Just like with timed_wait(), the timeout must be a * positive number. */ if (timeout < 0) acl_msg_panic("timed_connect: bad timeout: %d", timeout); /* * Start the connection, and handle all possible results. */ if (acl_sane_connect(sock, sa, len) == 0) return (0); errno = acl_last_error(); #ifdef ACL_UNIX if (errno != ACL_EINPROGRESS) return (-1); #elif defined(ACL_WINDOWS) if (errno != ACL_EINPROGRESS && errno != ACL_EWOULDBLOCK) return (-1); #endif /* * A connection is in progress. Wait for a limited amount of time for * something to happen. If nothing happens, report an error. */ if (acl_write_wait(sock, timeout) < 0) return (-1); /* * Something happened. Some Solaris 2 versions have getsockopt() itself * return the error, instead of returning it via the parameter list. */ len = sizeof(err); if (getsockopt(sock, SOL_SOCKET, SO_ERROR, (char *) &err, &len) < 0) { #ifdef SUNOS5 /* * Solaris 2.4's socket emulation doesn't allow you * to determine the error from a failed non-blocking * connect and just returns EPIPE. Create a fake * error message for connect. -- [email protected] */ if (errno == EPIPE) acl_set_error(ACL_ENOTCONN); #endif return (-1); } if (err != 0) { acl_set_error(err); return (-1); } else return (0); }
int acl_read_wait(ACL_SOCKET fd, int timeout) { const char *myname = "acl_read_wait"; struct pollfd fds; int delay = timeout * 1000; fds.events = POLLIN | POLLHUP | POLLERR; fds.fd = fd; acl_set_error(0); for (;;) { switch (poll(&fds, 1, delay)) { case -1: if (acl_last_error() == ACL_EINTR) continue; acl_msg_error("%s(%d), %s: poll error(%s), fd: %d", __FILE__, __LINE__, myname, acl_last_serror(), (int) fd); return -1; case 0: acl_set_error(ACL_ETIMEDOUT); return -1; default: if (fds.revents & (POLLHUP | POLLERR)) return -1; else if ((fds.revents & POLLIN)) return 0; else return -1; } } }
int acl_pthread_setspecific(acl_pthread_key_t key, void *value) { const char *myname = "acl_pthread_setspecific"; ACL_FIFO *tls_value_list_ptr = tls_value_list_get(); ACL_ITER iter; if (key < 0 || key >= ACL_PTHREAD_KEYS_MAX) { acl_msg_error("%s(%d): key(%d) invalid", myname, __LINE__, key); acl_set_error(ACL_EINVAL); return ACL_EINVAL; } if (__tls_key_list[key].key != key) { acl_msg_error("%s(%d): __tls_key_list[%d].key(%d) != key(%d)", myname, __LINE__, key, __tls_key_list[key].key, key); acl_set_error(ACL_EINVAL); return ACL_EINVAL; } acl_foreach(iter, tls_value_list_ptr) { TLS_VALUE *tls_value = (TLS_VALUE*) iter.data; if (tls_value->tls_key != NULL && tls_value->tls_key->key == key) { /* 如果相同的键存在则需要先释放旧数据 */ if (tls_value->tls_key->destructor && tls_value->value) tls_value->tls_key->destructor(tls_value->value); tls_value->tls_key = NULL; tls_value->value = NULL; break; } }
ACL_FILE_HANDLE acl_file_open(const char *filepath, int flags, int mode) { ACL_FILE_HANDLE fh; DWORD fileaccess = 0, fileshare = 0, filecreate = 0, fileattr = 0; /* decode the access flags */ switch (flags & (O_RDONLY | O_WRONLY | O_RDWR)) { case O_RDONLY: /* read access */ fileaccess = GENERIC_READ; break; case O_WRONLY: /* write access */ fileaccess = GENERIC_WRITE; if ((flags & O_APPEND) != 0) fileaccess |= FILE_APPEND_DATA; break; case O_RDWR: /* read and write access */ fileaccess = GENERIC_READ | GENERIC_WRITE; if ((flags & O_APPEND) != 0) fileaccess = GENERIC_READ | FILE_APPEND_DATA; break; default: /* error, bad flags */ acl_set_error(ERROR_INVALID_PARAMETER); return ACL_FILE_INVALID; } /* decode open/create method flags */ switch (flags & (O_CREAT | O_EXCL | O_TRUNC)) { case 0: case O_EXCL: /* ignore EXCL w/o CREAT */ filecreate = OPEN_EXISTING; break; case O_CREAT: filecreate = OPEN_ALWAYS; break; case O_CREAT | O_EXCL: case O_CREAT | O_TRUNC | O_EXCL: filecreate = CREATE_NEW; break; case O_TRUNC: case O_TRUNC | O_EXCL: /* ignore EXCL w/o CREAT */ filecreate = TRUNCATE_EXISTING; break; case O_CREAT | O_TRUNC: filecreate = CREATE_ALWAYS; break; default: /* this can't happen ... all cases are covered */ acl_set_error(ERROR_INVALID_PARAMETER); return ACL_FILE_INVALID; } fileshare |= FILE_SHARE_READ | FILE_SHARE_WRITE; fileattr = FILE_ATTRIBUTE_NORMAL; fh = CreateFile(filepath, fileaccess, fileshare, NULL, filecreate, fileattr, NULL); return fh; }
int acl_read_wait(ACL_SOCKET fd, int timeout) { const char *myname = "acl_read_wait"; struct pollfd fds; int delay = timeout * 1000; time_t begin; fds.events = POLLIN | POLLHUP | POLLERR; fds.fd = fd; acl_set_error(0); for (;;) { time(&begin); switch (poll(&fds, 1, delay)) { case -1: if (acl_last_error() == ACL_EINTR) continue; acl_msg_error("%s(%d), %s: poll error(%s), fd: %d", __FILE__, __LINE__, myname, acl_last_serror(), (int) fd); return -1; case 0: acl_msg_warn("%s(%d), %s: poll timeout: %s, fd: %d, " "delay: %d, spent: %ld", __FILE__, __LINE__, myname, acl_last_serror(), fd, delay, (long) (time(NULL) - begin)); acl_set_error(ACL_ETIMEDOUT); return -1; default: if (fds.revents & (POLLHUP | POLLERR)) { acl_msg_warn("%s(%d), %s: poll error: %s, " "fd: %d, delay: %d, spent: %ld", __FILE__, __LINE__, myname, acl_last_serror(), fd, delay, (long) (time(NULL) - begin)); return -1; } else if ((fds.revents & POLLIN)) return 0; else { acl_msg_warn("%s(%d), %s: poll error: %s, " "fd: %d, delay: %d, spent: %ld", __FILE__, __LINE__, myname, acl_last_serror(), fd, delay, (long) (time(NULL) - begin)); return -1; } } } }
int acl_pthread_attr_setstacksize(acl_pthread_attr_t *attr, size_t stacksize) { if (attr == NULL) { acl_set_error(ACL_EINVAL); return ACL_EINVAL; } if (stacksize < PTHREAD_STACK_MIN) { acl_set_error(ACL_EINVAL); return ACL_EINVAL; } attr->stacksize = stacksize; return 0; }
_tDIR * _topendir(const _TCHAR *dirname) { _TCHAR *name; int len; _tDIR *dir; HANDLE h; /* Allocate space for a copy of the directory name, plus * room for the "*.*" we will concatenate to the end. */ len = _tcslen(dirname); if ((name = malloc((len+5) * sizeof(_TCHAR))) == NULL) { acl_set_error(ENOMEM); return (NULL); } _tcscpy(name, dirname); if (len-- && name[len] != _TEXT(':') && name[len] != _TEXT('\\') && name[len] != _TEXT('/')) _tcscat(name,_TEXT("\\*.*")); else _tcscat(name,_TEXT("*.*")); /* Allocate space for a DIR structure. */ if ((dir = malloc(sizeof(_tDIR))) == NULL) { acl_set_error(ENOMEM); free(name); return (NULL); } /* Search for the first file to see if the directory exists, * and to obtain directory handle for future FindNextFile() calls. */ if ((h = FindFirstFile((LPSTR)name, (LPWIN32_FIND_DATA)&dir->_d_buf[0])) == (HANDLE)-1) { free(name); free(dir); acl_set_error(ENOTDIR); /* set error */ return (NULL); } /* Everything is OK. Save information in the DIR structure, return it. */ dir->_d_nfiles = 1; dir->_d_hdir = (unsigned long)h; dir->_d_dirname = name; dir->_d_magic = DIRMAGIC; return dir; }
int acl_readable(ACL_SOCKET fd) { const char *myname = "poll_read_wait"; struct pollfd fds; int delay = 0; fds.events = POLLIN; fds.fd = fd; acl_set_error(0); for (;;) { switch (poll(&fds, 1, delay)) { case -1: if (acl_last_error() == ACL_EINTR) continue; acl_msg_error("%s(%d), %s: poll error(%s), fd: %d", __FILE__, __LINE__, myname, acl_last_serror(), (int) fd); return -1; case 0: return 0; default: if ((fds.revents & POLLIN)) { return 1; } else if (fds.revents & (POLLHUP | POLLERR)) { return 1; } else { return 0; } } } }
struct _tdirent * _treaddir(_tDIR *dir) { WIN32_FIND_DATA *ff; /* Verify the handle. */ if (dir->_d_magic != DIRMAGIC) { acl_set_error(EBADF); return (NULL); } /* If all files in the buffer have been returned, find some more files. */ if (dir->_d_nfiles == 0) { if (FindNextFile((HANDLE)dir->_d_hdir, (LPWIN32_FIND_DATA)&dir->_d_buf[0]) != TRUE) return (NULL); } else dir->_d_nfiles = 0; /* Return the filename of the current file in the buffer. */ ff = (WIN32_FIND_DATA *)(dir->_d_buf); return ((struct _tdirent *)&ff->cFileName[0]); }
int acl_set_eugid(uid_t euid, gid_t egid) { int saved_error = acl_last_error(); char tbuf[256]; if (geteuid() != 0 && seteuid(0)) { acl_msg_error("set_eugid: seteuid(0): %s", acl_last_strerror(tbuf, sizeof(tbuf))); return -1; } if (setegid(egid) < 0) { acl_msg_error("set_eugid: setegid(%ld): %s", (long) egid, acl_last_strerror(tbuf, sizeof(tbuf))); return -1; } if (setgroups(1, &egid) < 0) { acl_msg_error("set_eugid: setgroups(%ld): %s", (long) egid, acl_last_strerror(tbuf, sizeof(tbuf))); return -1; } if (euid != 0 && seteuid(euid) < 0) { acl_msg_error("set_eugid: seteuid(%ld): %s", (long) euid, acl_last_strerror(tbuf, sizeof(tbuf))); return -1; } if (acl_msg_verbose) acl_msg_info("set_eugid: euid %ld egid %ld", (long) euid, (long) egid); acl_set_error(saved_error); return 0; }
static int poll_write_wait(ACL_SOCKET fd, int timeout) { const char *myname = "poll_write_wait"; struct pollfd fds; int delay = timeout * 1000; fds.events = POLLOUT | POLLHUP | POLLERR; fds.fd = fd; for (;;) { switch (poll(&fds, 1, delay)) { case -1: if (acl_last_error() != ACL_EINTR) { char tbuf[256]; acl_msg_error("%s: poll error(%s)", myname, acl_last_strerror(tbuf, sizeof(tbuf))); return (-1); } continue; case 0: acl_set_error(ACL_ETIMEDOUT); return (-1); default: if ((fds.revents & (POLLHUP | POLLERR)) || !(fds.revents & POLLOUT)) { return (-1); } return (0); } } }
int ssl_aio_stream::__ssl_send(ACL_SOCKET, const void *buf, size_t len, int, ACL_VSTREAM*, void *ctx) { #ifdef HAS_POLARSSL ssl_aio_stream* cli = (ssl_aio_stream*) ctx; int ret; while ((ret = ::ssl_write((ssl_context*) cli->ssl_, (unsigned char*) buf, len)) <= 0) { if (ret == POLARSSL_ERR_NET_WANT_READ || ret == POLARSSL_ERR_NET_WANT_WRITE) { if (acl_last_error() != ACL_EWOULDBLOCK) acl_set_error(ACL_EWOULDBLOCK); } return ACL_VSTREAM_EOF; } return ret; #else (void) buf; (void) len; (void) ctx; return -1; #endif }
int acl_readable(ACL_SOCKET fd) { const char *myname = "acl_readable"; struct timeval tv; fd_set rfds, xfds; int errnum; /* * Sanity checks. */ if ((unsigned) fd >= FD_SETSIZE) acl_msg_fatal("%s(%d), %s: fd %d does not fit in " "FD_SETSIZE: %d", __FILE__, __LINE__, myname, (int) fd, FD_SETSIZE); /* * Initialize. */ FD_ZERO(&rfds); FD_SET(fd, &rfds); FD_ZERO(&xfds); FD_SET(fd, &xfds); tv.tv_sec = 0; tv.tv_usec = 0; acl_set_error(0); /* * Loop until we have an authoritative answer. */ for (;;) { switch (select((int) fd + 1, &rfds, (fd_set *) 0, &xfds, &tv)) { case -1: errnum = acl_last_error(); #ifdef ACL_WINDOWS if (errnum == WSAEINPROGRESS || errnum == WSAEWOULDBLOCK || errnum == ACL_EINTR) { continue; } #else if (errnum == ACL_EINTR) continue; #endif acl_msg_error("%s(%d), %s: select error(%s), fd: %d", __FILE__, __LINE__, myname, acl_last_serror(), (int) fd); return -1; case 0: return 0; default: return FD_ISSET(fd, &rfds); } } }
int acl_pthread_attr_setdetachstate(acl_pthread_attr_t *thr_attr, int detached) { if (thr_attr == NULL) { acl_set_error(ACL_EINVAL); return ACL_EINVAL; } thr_attr->detached = detached; return 0; }
int acl_pthread_attr_destroy(acl_pthread_attr_t *thr_attr) { if (thr_attr == NULL) { acl_set_error(ACL_EINVAL); return ACL_EINVAL; } memset(&thr_attr->attr, 0, sizeof(thr_attr->attr)); return 0; }
int acl_read_wait(ACL_SOCKET fd, int timeout) { const char *myname = "acl_read_wait"; int op = EPOLL_CTL_ADD, delay = timeout * 1000, *epoll_fd; struct epoll_event ee, events[1]; acl_assert(acl_pthread_once(&epoll_once, thread_epoll_init) == 0); epoll_fd = (int*) acl_pthread_getspecific(epoll_key); if (epoll_fd == NULL) { epoll_fd = (int*) acl_mymalloc(sizeof(int)); acl_assert(acl_pthread_setspecific(epoll_key, epoll_fd) == 0); if ((unsigned long) acl_pthread_self() == acl_main_thread_self()) { main_epoll_read_fd = epoll_fd; atexit(main_epoll_end); } *epoll_fd = epoll_create(1); } ee.events = EPOLLIN | EPOLLHUP | EPOLLERR; ee.data.u64 = 0; ee.data.fd = fd; if (epoll_ctl(*epoll_fd, op, fd, &ee) == -1) { acl_msg_error("%s(%d): epoll_ctl error: %s, fd: %d", myname, __LINE__, acl_last_serror(), fd); return -1; } if (epoll_wait(*epoll_fd, events, 1, delay) == -1) { acl_msg_error("%s(%d): epoll_wait error: %s, fd: %d", myname, __LINE__, acl_last_serror(), fd); return -1; } if ((events[0].events & (EPOLLERR | EPOLLHUP)) != 0) return -1; if ((events[0].events & EPOLLIN) == 0) { acl_set_error(ACL_ETIMEDOUT); return -1; } ee.events = 0; ee.data.u64 = 0; ee.data.fd = fd; if (epoll_ctl(*epoll_fd, EPOLL_CTL_DEL, fd, &ee) == -1) { acl_msg_error("%s(%d): epoll_ctl error: %s, fd: %d", myname, __LINE__, acl_last_serror(), fd); return -1; } return 0; }
int acl_write_wait(ACL_SOCKET fd, int timeout) { const char *myname = "acl_write_wait"; struct pollfd fds; int delay = timeout * 1000; fds.events = POLLOUT | POLLHUP | POLLERR; fds.fd = fd; acl_set_error(0); for (;;) { switch (poll(&fds, 1, delay)) { case -1: if (acl_last_error() == ACL_EINTR) continue; acl_msg_error("%s(%d), %s: poll error(%s), fd: %d", __FILE__, __LINE__, myname, acl_last_serror(), (int) fd); return -1; case 0: acl_set_error(ACL_ETIMEDOUT); return -1; default: if ((fds.revents & (POLLHUP | POLLERR))) { acl_msg_error("%s(%d), %s: fd: %d," "POLLHUP: %s, POLLERR: %s", __FILE__, __LINE__, myname, fd, fds.revents & POLLHUP ? "yes" : "no", fds.revents & POLLERR ? "yes" : "no"); return -1; } if (fds.revents & POLLOUT) return 0; acl_msg_error("%s(%d), %s: unknown error, fd: %d", __FILE__, __LINE__, myname, fd); return -1; } } }
bool thread_mutex::unlock(void) { int ret = acl_pthread_mutex_unlock(mutex_); if (ret) { #ifdef ACL_UNIX acl_set_error(ret); logger_error("pthread_mutex_unlock error %s", last_serror()); #endif return false; } return true; }
int acl_pthread_once(acl_pthread_once_t *once_control, void (*init_routine)(void)) { int n = 0; if (once_control == NULL || init_routine == NULL) { acl_set_error(ACL_EINVAL); return ACL_EINVAL; } /* 只有第一个调用 InterlockedCompareExchange 的线程才会执行 * init_routine, 后续线程永远在 InterlockedCompareExchange * 外运行,并且一直进入空循环直至第一个线程执行 init_routine * 完毕并且将 *once_control 重新赋值, 只有在多核环境中多个线程 * 同时运行至此时才有可能出现短暂的后续线程空循环现象,如果 * 多个线程顺序至此,则因为 *once_control 已经被第一个线程重新 * 赋值而不会进入循环体内只所以如此处理,是为了保证所有线程在 * 调用 acl_pthread_once 返回前 init_routine 必须被调用且仅能 * 被调用一次, 但在VC6下,InterlockedCompareExchange 接口定义 * 有些怪异,需要做硬性指定参数类型,参见 <Windows 高级编程指南> * Jeffrey Richter, 366 页 */ while (1) { #ifdef MS_VC6 LONG prev = InterlockedCompareExchange((PVOID) once_control, (PVOID) 1, (PVOID) ACL_PTHREAD_ONCE_INIT); #else LONG prev = InterlockedCompareExchange( once_control, 1, ACL_PTHREAD_ONCE_INIT); #endif if (prev == 2) return 0; else if (prev == 0) { /* 只有第一个线程才会至此 */ init_routine(); /* 将 *conce_control 重新赋值以使后续线程不进入 while * 循环或从 while 循环中跳出 */ InterlockedExchange(once_control, 2); return 0; } else { acl_assert(prev == 1); /* 防止空循环过多地浪费CPU */ Sleep(1); /** sleep 1ms */ } } return 1; /* 不可达代码,避免编译器报警告 */ }
int _tclosedir(_tDIR *dir) { /* Verify the handle. */ if (dir == NULL || dir->_d_magic != DIRMAGIC) { acl_set_error(EBADF); return (-1); } dir->_d_magic = 0; /* prevent accidental use after closing */ FindClose((HANDLE)dir->_d_hdir);/* close directory handle */ free(dir->_d_dirname); /* free directory name */ free(dir); /* free directory structure */ return 0; }
int acl_pthread_key_create(acl_pthread_key_t *key_ptr, void (*destructor)(void*)) { const char *myname = "acl_pthread_key_create"; acl_pthread_once(&__create_thread_control_once, acl_pthread_init_once); *key_ptr = TlsAlloc(); if (*key_ptr == ACL_TLS_OUT_OF_INDEXES) { acl_set_error(ACL_ENOMEM); return ACL_ENOMEM; } else if (*key_ptr >= ACL_PTHREAD_KEYS_MAX) { acl_msg_error("%s(%d): key(%d) > ACL_PTHREAD_KEYS_MAX(%d)", myname, __LINE__, *key_ptr, ACL_PTHREAD_KEYS_MAX); TlsFree(*key_ptr); *key_ptr = ACL_TLS_OUT_OF_INDEXES; acl_set_error(ACL_ENOMEM); return ACL_ENOMEM; } __tls_key_list[*key_ptr].destructor = destructor; __tls_key_list[*key_ptr].key = *key_ptr; return 0; }
int acl_pthread_attr_init(acl_pthread_attr_t *thr_attr) { if (thr_attr == NULL) { acl_set_error(ACL_EINVAL); return ACL_EINVAL; } memset(&thr_attr->attr, 0, sizeof(thr_attr->attr)); thr_attr->attr.bInheritHandle = 1; thr_attr->attr.lpSecurityDescriptor = NULL; thr_attr->attr.nLength = sizeof(SECURITY_ATTRIBUTES); thr_attr->stacksize = 0; thr_attr->detached = 0; return 0; }
static int __read_wait(ACL_SOCKET fd, int timeout) { fd_set read_fds; fd_set except_fds; struct timeval tv; struct timeval *tp; #ifdef ACL_UNIX /* * Sanity checks. */ acl_assert(FD_SETSIZE > (unsigned) fd); #endif /* * Use select() so we do not depend on alarm() and on signal() handlers. * Restart the select when interrupted by some signal. Some select() * implementations reduce the time to wait when interrupted, which is * exactly what we want. */ FD_ZERO(&read_fds); FD_SET(fd, &read_fds); FD_ZERO(&except_fds); FD_SET(fd, &except_fds); if (timeout >= 0) { tv.tv_usec = 0; tv.tv_sec = timeout; tp = &tv; } else tp = 0; for (;;) { switch (select((int) fd + 1, &read_fds, (fd_set *) 0, &except_fds, tp)) { case -1: if (acl_last_error() != ACL_EINTR) return -1; continue; case 0: acl_set_error(ACL_ETIMEDOUT); return (-1); default: return (0); } } }
int acl_timed_waitpid(pid_t pid, ACL_WAIT_STATUS_T *statusp, int options, int time_limit) { const char *myname = "timed_waitpid"; struct sigaction action; struct sigaction old_action; int time_left; int wpid; char tbuf[256]; /* * Sanity checks. */ if (time_limit <= 0) acl_msg_panic("%s: bad time limit: %d", myname, time_limit); /* * Set up a timer. */ sigemptyset(&action.sa_mask); action.sa_flags = 0; action.sa_handler = timed_wait_alarm; if (sigaction(SIGALRM, &action, &old_action) < 0) acl_msg_fatal("%s: sigaction(SIGALRM): %s", myname, acl_last_strerror(tbuf, sizeof(tbuf))); timed_wait_expired = 0; time_left = alarm(time_limit); /* * Wait for only a limited amount of time. */ if ((wpid = waitpid(pid, statusp, options)) < 0 && timed_wait_expired) acl_set_error(ETIMEDOUT); /* * Cleanup. */ alarm(0); if (sigaction(SIGALRM, &old_action, (struct sigaction *) 0) < 0) acl_msg_fatal("%s: sigaction(SIGALRM): %s", myname, acl_last_strerror(tbuf, sizeof(tbuf))); if (time_left) alarm(time_left); return (wpid); }
void acl_set_ugid(uid_t uid, gid_t gid) { int saved_error = acl_last_error(); char tbuf[256]; if (geteuid() != 0) if (seteuid(0) < 0) acl_msg_fatal("seteuid(0): %s", acl_last_strerror(tbuf, sizeof(tbuf))); if (setgid(gid) < 0) acl_msg_fatal("setgid(%ld): %s", (long) gid, acl_last_strerror(tbuf, sizeof(tbuf))); if (setgroups(1, &gid) < 0) acl_msg_fatal("setgroups(1, &%ld): %s", (long) gid, acl_last_strerror(tbuf, sizeof(tbuf))); if (setuid(uid) < 0) acl_msg_fatal("setuid(%ld): %s", (long) uid, acl_last_strerror(tbuf, sizeof(tbuf))); if (acl_msg_verbose > 1) acl_msg_info("setugid: uid %ld gid %ld", (long) uid, (long) gid); acl_set_error(saved_error); }
int acl_readable(ACL_SOCKET fd) { struct pollfd fds; int delay = 0; fds.events = POLLIN | POLLPRI; fds.fd = fd; acl_set_error(0); for (;;) { switch (__sys_poll(&fds, 1, delay)) { #ifdef ACL_WINDOWS case SOCKET_ERROR: #else case -1: #endif if (acl_last_error() == ACL_EINTR) continue; acl_msg_error("%s(%d), %s: poll error(%s), fd: %d", __FILE__, __LINE__, __FUNCTION__, acl_last_serror(), (int) fd); return -1; case 0: return 0; default: if ((fds.revents & POLLIN)) { return 1; } else if (fds.revents & (POLLHUP | POLLERR)) { return 1; } else { return 0; } } } }
int acl_myflock(ACL_FILE_HANDLE fd, int lock_style, int operation) { int status = 0; /* * Sanity check. */ if ((operation & (ACL_FLOCK_OP_BITS)) != operation) acl_msg_panic("myflock: improper operation type: 0x%x", operation); switch (lock_style) { /* * flock() does exactly what we need. Too bad it is not standard. */ #ifdef ACL_HAS_FLOCK_LOCK case ACL_FLOCK_STYLE_FLOCK: { static int lock_ops[] = { LOCK_UN, LOCK_SH, LOCK_EX, -1, -1, LOCK_SH | LOCK_NB, LOCK_EX | LOCK_NB, -1 }; status = flock(fd, lock_ops[operation]); break; } #endif /* * fcntl() is standard and does more than we need, but we can handle * it. */ #ifdef ACL_HAS_FCNTL_LOCK case ACL_FLOCK_STYLE_FCNTL: { struct flock lock; int request; static int lock_ops[] = { F_UNLCK, F_RDLCK, F_WRLCK }; memset((char *) &lock, 0, sizeof(lock)); lock.l_type = lock_ops[operation & ~ACL_FLOCK_OP_NOWAIT]; request = (operation & ACL_FLOCK_OP_NOWAIT) ? F_SETLK : F_SETLKW; while ((status = fcntl(fd, request, &lock)) < 0 && request == F_SETLKW && (acl_last_error() == ACL_EINTR || acl_last_error() == ENOLCK || acl_last_error() == EDEADLK)) sleep(1); break; } #endif default: acl_msg_panic("myflock: unsupported lock style: 0x%x", lock_style); } /* * Return a consistent result. Some systems return EACCES when a lock is * taken by someone else, and that would complicate error processing. */ if (status < 0 && (operation & ACL_FLOCK_OP_NOWAIT) != 0) { char error = acl_last_error(); if (error == ACL_EAGAIN || error == ACL_EWOULDBLOCK || error == EACCES) acl_set_error(ACL_EAGAIN); } return (status); }
int acl_read_wait(ACL_SOCKET fd, int timeout) { const char *myname = "acl_read_wait"; fd_set rfds, xfds; struct timeval tv; struct timeval *tp; int errnum; time_t begin; /* * Sanity checks. */ #ifndef ACL_WINDOWS if (FD_SETSIZE <= (unsigned) fd) acl_msg_fatal("%s(%d), %s: descriptor %d does not fit " "FD_SETSIZE %d", __FILE__, __LINE__, myname, (int) fd, FD_SETSIZE); #endif /* * Guard the write() with select() so we do not depend on alarm() * and on signal() handlers. Restart the select when interrupted * by some signal. Some select() implementations may reduce the * time to wait when interrupted, which is exactly what we want. */ FD_ZERO(&rfds); FD_SET(fd, &rfds); FD_ZERO(&xfds); FD_SET(fd, &xfds); if (timeout >= 0) { tv.tv_usec = 0; tv.tv_sec = timeout; tp = &tv; } else tp = 0; acl_set_error(0); for (;;) { time(&begin); #ifdef ACL_WINDOWS switch (select(1, &rfds, (fd_set *) 0, &xfds, tp)) { #else switch (select(fd + 1, &rfds, (fd_set *) 0, &xfds, tp)) { #endif case -1: errnum = acl_last_error(); #ifdef ACL_WINDOWS if (errnum == WSAEINPROGRESS || errnum == WSAEWOULDBLOCK || errnum == ACL_EINTR) { continue; } #else if (errnum == ACL_EINTR) continue; #endif acl_msg_error("%s(%d), %s: select error(%s), fd: %d", __FILE__, __LINE__, myname, acl_last_serror(), (int) fd); return -1; case 0: acl_msg_warn("%s(%d), %s: poll timeout: %s, fd: %d, " "timeout: %d, spent: %ld", __FILE__, __LINE__, myname, acl_last_serror(), fd, timeout, (long) (time(NULL) - begin)); acl_set_error(ACL_ETIMEDOUT); return -1; default: return 0; } } }
int acl_read_wait(ACL_SOCKET fd, int timeout) { const char *myname = "acl_read_wait"; int delay = timeout * 1000, ret; EPOLL_CTX *epoll_ctx; struct epoll_event ee, events[1]; time_t begin; acl_assert(acl_pthread_once(&epoll_once, thread_epoll_once) == 0); epoll_ctx = (EPOLL_CTX*) acl_pthread_getspecific(epoll_key); if (epoll_ctx == NULL) epoll_ctx = thread_epoll_init(); ee.events = EPOLLIN | EPOLLHUP | EPOLLERR; ee.data.u64 = 0; ee.data.fd = fd; if (epoll_ctl(epoll_ctx->epfd, EPOLL_CTL_ADD, fd, &ee) == -1 && acl_last_error() != EEXIST) { acl_msg_error("%s(%d): epoll_ctl error: %s, fd: %d, epfd: %d," " tid: %lu, %lu", myname, __LINE__, acl_last_serror(), fd, epoll_ctx->epfd, epoll_ctx->tid, acl_pthread_self()); return -1; } for (;;) { time(&begin); ret = epoll_wait(epoll_ctx->epfd, events, 1, delay); if (ret == -1) { if (acl_last_error() == ACL_EINTR) { acl_msg_warn(">>>>catch EINTR, try again<<<"); continue; } acl_msg_error("%s(%d): epoll_wait error: %s, fd: %d," " epfd: %d, tid: %lu, %lu", myname, __LINE__, acl_last_serror(), fd, epoll_ctx->epfd, epoll_ctx->tid, acl_pthread_self()); ret = -1; break; } else if (ret == 0) { acl_msg_warn("%s(%d), %s: poll timeout: %s, fd: %d, " "delay: %d, spent: %ld", __FILE__, __LINE__, myname, acl_last_serror(), fd, delay, (long) (time(NULL) - begin)); acl_set_error(ACL_ETIMEDOUT); ret = -1; break; } else if ((events[0].events & (EPOLLERR | EPOLLHUP)) != 0) { acl_msg_warn("%s(%d), %s: poll error: %s, fd: %d, " "delay: %d, spent: %ld", __FILE__, __LINE__, myname, acl_last_serror(), fd, delay, (long) (time(NULL) - begin)); ret = -1; } else if ((events[0].events & EPOLLIN) == 0) { acl_msg_warn("%s(%d), %s: poll error: %s, fd: %d, " "delay: %d, spent: %ld", __FILE__, __LINE__, myname, acl_last_serror(), fd, delay, (long) (time(NULL) - begin)); acl_set_error(ACL_ETIMEDOUT); ret = -1; } else ret = 0; break; } ee.events = 0; ee.data.u64 = 0; ee.data.fd = fd; if (epoll_ctl(epoll_ctx->epfd, EPOLL_CTL_DEL, fd, &ee) == -1) { acl_msg_error("%s(%d): epoll_ctl error: %s, fd: %d, epfd: %d," " tid: %lu, %lu", myname, __LINE__, acl_last_serror(), fd, epoll_ctx->epfd, epoll_ctx->tid, acl_pthread_self()); return -1; } return ret; }
int acl_pthread_create(acl_pthread_t *thread, acl_pthread_attr_t *attr, void *(*start_routine)(void *), void *arg) { const char *myname = "acl_pthread_create"; acl_pthread_t *h_thread; HANDLE handle; unsigned long id, flag; if (thread == NULL) { acl_msg_error("%s, %s(%d): input invalid", __FILE__, myname, __LINE__); acl_set_error(ACL_EINVAL); return ACL_EINVAL; } acl_pthread_once(&__create_thread_control_once, acl_pthread_init_once); memset(thread, 0, sizeof(acl_pthread_t)); h_thread = acl_default_calloc(__FILE__, __LINE__, 1, sizeof(acl_pthread_t)); if (h_thread == NULL) { acl_msg_error("%s, %s(%d): calloc error(%s)", __FILE__, myname, __LINE__, acl_last_serror()); acl_set_error(ACL_ENOMEM); return ACL_ENOMEM; } if (attr != NULL) h_thread->detached = attr->detached; else h_thread->detached = 1; h_thread->start_routine = start_routine; h_thread->routine_arg = arg; if (__thread_inited) { acl_pthread_mutex_lock(&__thread_lock); flag = 0; } else flag = CREATE_SUSPENDED; #ifdef ACL_WIN32_STDC h_thread->handle = handle = (HANDLE) _beginthreadex(NULL, attr ? (unsigned int) attr->stacksize : 0, RunThreadWrap, (void *) h_thread, flag, &id); #else h_thread->handle = handle = CreateThread(NULL, attr ? attr->stacksize : 0,, RunThreadWrap, h_thread, flag, &id); #endif if (__thread_inited) acl_pthread_mutex_unlock(&__thread_lock); else if (flag == CREATE_SUSPENDED && handle != 0) ResumeThread(handle); if (handle == 0) { acl_msg_error("%s, %s(%d): CreateThread error(%s)", __FILE__, myname, __LINE__, acl_last_serror()); return -1; } thread->start_routine = start_routine; thread->routine_arg = arg; thread->id = id; thread->handle = 0; /* 根据线程的属性来确定线程创建时是分离模式还是非分离模式 */ if (attr == NULL || attr->detached) { thread->detached = 1; return 0; } thread->detached = 0; thread->handle = handle; return 0; }