uv_err_t uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) { unsigned int numcpus; uv_cpu_info_t* ci; *cpu_infos = NULL; *count = 0; numcpus = sysconf(_SC_NPROCESSORS_ONLN); assert(numcpus != (unsigned int)-1); assert(numcpus != 0); ci = calloc(numcpus, sizeof(*ci)); if (ci == NULL) return uv__new_sys_error(ENOMEM); if (read_models(numcpus, ci)) { SAVE_ERRNO(uv_free_cpu_info(ci, numcpus)); return uv__new_sys_error(errno); } if (read_times(numcpus, ci)) { SAVE_ERRNO(uv_free_cpu_info(ci, numcpus)); return uv__new_sys_error(errno); } /* read_models() on x86 also reads the CPU speed from /proc/cpuinfo. * We don't check for errors here. Worst case, the field is left zero. */ if (ci[0].speed == 0) read_speeds(numcpus, ci); *cpu_infos = ci; *count = numcpus; return uv_ok_; }
int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) { unsigned int ticks = (unsigned int)sysconf(_SC_CLK_TCK), multiplier = ((uint64_t)1000L / ticks), cpuspeed; uint64_t info[CPUSTATES]; char model[512]; int numcpus = 1; static int which[] = {CTL_HW,HW_MODEL,0}; size_t size; int i; uv_cpu_info_t* cpu_info; size = sizeof(model); if (sysctl(which, 2, &model, &size, NULL, 0)) return -errno; which[1] = HW_NCPU; size = sizeof(numcpus); if (sysctl(which, 2, &numcpus, &size, NULL, 0)) return -errno; *cpu_infos = malloc(numcpus * sizeof(**cpu_infos)); if (!(*cpu_infos)) return -ENOMEM; *count = numcpus; which[1] = HW_CPUSPEED; size = sizeof(cpuspeed); if (sysctl(which, 2, &cpuspeed, &size, NULL, 0)) { SAVE_ERRNO(free(*cpu_infos)); return -errno; } size = sizeof(info); which[0] = CTL_KERN; which[1] = KERN_CPTIME2; for (i = 0; i < numcpus; i++) { which[2] = i; size = sizeof(info); if (sysctl(which, 3, &info, &size, NULL, 0)) { SAVE_ERRNO(free(*cpu_infos)); return -errno; } cpu_info = &(*cpu_infos)[i]; cpu_info->cpu_times.user = (uint64_t)(info[CP_USER]) * multiplier; cpu_info->cpu_times.nice = (uint64_t)(info[CP_NICE]) * multiplier; cpu_info->cpu_times.sys = (uint64_t)(info[CP_SYS]) * multiplier; cpu_info->cpu_times.idle = (uint64_t)(info[CP_IDLE]) * multiplier; cpu_info->cpu_times.irq = (uint64_t)(info[CP_INTR]) * multiplier; cpu_info->model = strdup(model); cpu_info->speed = cpuspeed; } return 0; }
int uv_exepath(char* buffer, size_t* size) { uint32_t usize; int result; char* path; char* fullpath; if (buffer == NULL || size == NULL) return -EINVAL; usize = *size; result = _NSGetExecutablePath(buffer, &usize); if (result) return result; path = malloc(2 * PATH_MAX); fullpath = realpath(buffer, path); if (fullpath == NULL) { SAVE_ERRNO(free(path)); return -errno; } strncpy(buffer, fullpath, *size); free(fullpath); *size = strlen(buffer); return 0; }
static void invokeArray(JNIEnv* env, jlong ctxAddress, jbyteArray paramBuffer, void* returnBuffer) { Function* ctx = (Function *) j2p(ctxAddress); void** ffiArgs = { NULL }; jbyte *tmpBuffer = NULL; if (ctx->cif.nargs > 0) { unsigned int i; tmpBuffer = alloca(ctx->cif.nargs * PARAM_SIZE); ffiArgs = alloca(ctx->cif.nargs * sizeof(void *)); (*env)->GetByteArrayRegion(env, paramBuffer, 0, ctx->cif.nargs * PARAM_SIZE, tmpBuffer); for (i = 0; i < ctx->cif.nargs; ++i) { if (unlikely(ctx->cif.arg_types[i]->type == FFI_TYPE_STRUCT)) { ffiArgs[i] = *(void **) &tmpBuffer[i * PARAM_SIZE]; } else { ffiArgs[i] = &tmpBuffer[i * PARAM_SIZE]; } } } ffi_call(&ctx->cif, FFI_FN(ctx->function), returnBuffer, ffiArgs); SAVE_ERRNO(ctx); }
/* * Class: com_kenai_jffi_Foreign * Method: invokeArrayReturnStruct * Signature: (J[B[B)V */ JNIEXPORT void JNICALL Java_com_kenai_jffi_Foreign_invokeArrayReturnStruct(JNIEnv* env, jclass self, jlong ctxAddress, jbyteArray paramBuffer, jbyteArray returnBuffer, jint offset) { Function* ctx = (Function *) j2p(ctxAddress); jbyte* retval = alloca(ctx->cif.rtype->size); jbyte* tmpBuffer; void** ffiArgs; int i; // // Due to the undocumented and somewhat strange struct-return handling when // using ffi_raw_call(), we convert from raw to ptr array, then call via normal // ffi_call // ffiArgs = alloca(ctx->cif.nargs * sizeof(void *)); #ifdef USE_RAW tmpBuffer = alloca(ctx->rawParameterSize); (*env)->GetByteArrayRegion(env, paramBuffer, 0, ctx->rawParameterSize, tmpBuffer); for (i = 0; i < (int) ctx->cif.nargs; ++i) { ffiArgs[i] = (tmpBuffer + ctx->rawParamOffsets[i]); } #else tmpBuffer = alloca(ctx->cif.nargs * PARAM_SIZE); (*env)->GetByteArrayRegion(env, paramBuffer, 0, ctx->cif.nargs * PARAM_SIZE, tmpBuffer); for (i = 0; i < (int) ctx->cif.nargs; ++i) { ffiArgs[i] = &tmpBuffer[i * PARAM_SIZE]; } #endif ffi_call(&ctx->cif, FFI_FN(ctx->function), retval, ffiArgs); SAVE_ERRNO(ctx); (*env)->SetByteArrayRegion(env, returnBuffer, offset, ctx->cif.rtype->size, retval); }
int uv__close(int fd) { assert(fd > STDERR_FILENO); /* Catch stdio close bugs. */ #if defined(__MVS__) SAVE_ERRNO(epoll_file_close(fd)); #endif return uv__close_nocheckstdio(fd); }
uv_err_t uv_resident_set_memory(size_t* rss) { char buf[1024]; const char* s; ssize_t n; long val; int fd; int i; do fd = open("/proc/self/stat", O_RDONLY); while (fd == -1 && errno == EINTR); if (fd == -1) return uv__new_sys_error(errno); do n = read(fd, buf, sizeof(buf) - 1); while (n == -1 && errno == EINTR); SAVE_ERRNO(close(fd)); if (n == -1) return uv__new_sys_error(errno); buf[n] = '\0'; s = strchr(buf, ' '); if (s == NULL) goto err; s += 1; if (*s != '(') goto err; s = strchr(s, ')'); if (s == NULL) goto err; for (i = 1; i <= 22; i++) { s = strchr(s + 1, ' '); if (s == NULL) goto err; } errno = 0; val = strtol(s, NULL, 10); if (errno != 0) goto err; if (val < 0) goto err; *rss = val * getpagesize(); return uv_ok_; err: return uv__new_artificial_error(UV_EINVAL); }
/* This function is not execve-safe, there is a race window * between the call to dup() and fcntl(FD_CLOEXEC). */ int uv__dup(int fd) { fd = dup(fd); if (fd == -1) return -1; if (uv__cloexec(fd, 1)) { SAVE_ERRNO(uv__close(fd)); return -1; } return fd; }
static void invokeArray(JNIEnv* env, jlong ctxAddress, jbyteArray paramBuffer, void* returnBuffer) { Function* ctx = (Function *) j2p(ctxAddress); FFIValue tmpValue; jbyte *tmpBuffer = (jbyte *) &tmpValue; if (likely(ctx->cif.nargs > 0)) { tmpBuffer = alloca(ctx->cif.bytes); (*env)->GetByteArrayRegion(env, paramBuffer, 0, ctx->rawParameterSize, tmpBuffer); } ffi_raw_call(&ctx->cif, FFI_FN(ctx->function), returnBuffer, (ffi_raw *) tmpBuffer); SAVE_ERRNO(ctx); }
static int new_inotify_fd(void) { #if HAVE_INOTIFY_INIT1 return inotify_init1(IN_NONBLOCK | IN_CLOEXEC); #else int fd; if ((fd = inotify_init()) == -1) return -1; if (uv__cloexec(fd, 1) || uv__nonblock(fd, 1)) { SAVE_ERRNO(uv__close(fd)); fd = -1; } return fd; #endif }
static int new_inotify_fd(void) { int fd; fd = uv__inotify_init1(UV__IN_NONBLOCK | UV__IN_CLOEXEC); if (fd != -1) return fd; if (errno != ENOSYS) return -1; if ((fd = uv__inotify_init()) == -1) return -1; if (uv__cloexec(fd, 1) || uv__nonblock(fd, 1)) { SAVE_ERRNO(close(fd)); return -1; } return fd; }
void uv__io_poll(uv_loop_t* loop, int timeout) { struct pollfd events[1024]; struct pollfd pqry; struct pollfd* pe; struct poll_ctl pc; QUEUE* q; uv__io_t* w; uint64_t base; uint64_t diff; int nevents; int count; int nfds; int i; int rc; int add_failed; if (loop->nfds == 0) { assert(QUEUE_EMPTY(&loop->watcher_queue)); return; } while (!QUEUE_EMPTY(&loop->watcher_queue)) { q = QUEUE_HEAD(&loop->watcher_queue); QUEUE_REMOVE(q); QUEUE_INIT(q); w = QUEUE_DATA(q, uv__io_t, watcher_queue); assert(w->pevents != 0); assert(w->fd >= 0); assert(w->fd < (int) loop->nwatchers); pc.events = w->pevents; pc.fd = w->fd; add_failed = 0; if (w->events == 0) { pc.cmd = PS_ADD; if (pollset_ctl(loop->backend_fd, &pc, 1)) { if (errno != EINVAL) { assert(0 && "Failed to add file descriptor (pc.fd) to pollset"); abort(); } /* Check if the fd is already in the pollset */ pqry.fd = pc.fd; rc = pollset_query(loop->backend_fd, &pqry); switch (rc) { case -1: assert(0 && "Failed to query pollset for file descriptor"); abort(); case 0: assert(0 && "Pollset does not contain file descriptor"); abort(); } /* If we got here then the pollset already contained the file descriptor even though * we didn't think it should. This probably shouldn't happen, but we can continue. */ add_failed = 1; } } if (w->events != 0 || add_failed) { /* Modify, potentially removing events -- need to delete then add. * Could maybe mod if we knew for sure no events are removed, but * content of w->events is handled above as not reliable (falls back) * so may require a pollset_query() which would have to be pretty cheap * compared to a PS_DELETE to be worth optimizing. Alternatively, could * lazily remove events, squelching them in the mean time. */ pc.cmd = PS_DELETE; if (pollset_ctl(loop->backend_fd, &pc, 1)) { assert(0 && "Failed to delete file descriptor (pc.fd) from pollset"); abort(); } pc.cmd = PS_ADD; if (pollset_ctl(loop->backend_fd, &pc, 1)) { assert(0 && "Failed to add file descriptor (pc.fd) to pollset"); abort(); } } w->events = w->pevents; } assert(timeout >= -1); base = loop->time; count = 48; /* Benchmarks suggest this gives the best throughput. */ for (;;) { nfds = pollset_poll(loop->backend_fd, events, ARRAY_SIZE(events), timeout); /* Update loop->time unconditionally. It's tempting to skip the update when * timeout == 0 (i.e. non-blocking poll) but there is no guarantee that the * operating system didn't reschedule our process while in the syscall. */ SAVE_ERRNO(uv__update_time(loop)); if (nfds == 0) { assert(timeout != -1); return; } if (nfds == -1) { if (errno != EINTR) { abort(); } if (timeout == -1) continue; if (timeout == 0) return; /* Interrupted by a signal. Update timeout and poll again. */ goto update_timeout; } nevents = 0; assert(loop->watchers != NULL); loop->watchers[loop->nwatchers] = (void*) events; loop->watchers[loop->nwatchers + 1] = (void*) (uintptr_t) nfds; for (i = 0; i < nfds; i++) { pe = events + i; pc.cmd = PS_DELETE; pc.fd = pe->fd; /* Skip invalidated events, see uv__platform_invalidate_fd */ if (pc.fd == -1) continue; assert(pc.fd >= 0); assert((unsigned) pc.fd < loop->nwatchers); w = loop->watchers[pc.fd]; if (w == NULL) { /* File descriptor that we've stopped watching, disarm it. * * Ignore all errors because we may be racing with another thread * when the file descriptor is closed. */ pollset_ctl(loop->backend_fd, &pc, 1); continue; } w->cb(loop, w, pe->revents); nevents++; } loop->watchers[loop->nwatchers] = NULL; loop->watchers[loop->nwatchers + 1] = NULL; if (nevents != 0) { if (nfds == ARRAY_SIZE(events) && --count != 0) { /* Poll for more events but don't block this time. */ timeout = 0; continue; } return; } if (timeout == 0) return; if (timeout == -1) continue; update_timeout: assert(timeout > 0); diff = loop->time - base; if (diff >= (uint64_t) timeout) return; timeout -= diff; } }
void uv__io_poll(uv_loop_t* loop, int timeout) { struct kevent events[1024]; struct kevent* ev; struct timespec spec; unsigned int nevents; unsigned int revents; QUEUE* q; uint64_t base; uint64_t diff; uv__io_t* w; int filter; int fflags; int count; int nfds; int fd; int op; int i; if (loop->nfds == 0) { assert(QUEUE_EMPTY(&loop->watcher_queue)); return; } nevents = 0; while (!QUEUE_EMPTY(&loop->watcher_queue)) { q = QUEUE_HEAD(&loop->watcher_queue); QUEUE_REMOVE(q); QUEUE_INIT(q); w = QUEUE_DATA(q, uv__io_t, watcher_queue); assert(w->pevents != 0); assert(w->fd >= 0); assert(w->fd < (int) loop->nwatchers); if ((w->events & UV__POLLIN) == 0 && (w->pevents & UV__POLLIN) != 0) { filter = EVFILT_READ; fflags = 0; op = EV_ADD; if (w->cb == uv__fs_event) { filter = EVFILT_VNODE; fflags = NOTE_ATTRIB | NOTE_WRITE | NOTE_RENAME | NOTE_DELETE | NOTE_EXTEND | NOTE_REVOKE; op = EV_ADD | EV_ONESHOT; /* Stop the event from firing repeatedly. */ } EV_SET(events + nevents, w->fd, filter, op, fflags, 0, 0); if (++nevents == ARRAY_SIZE(events)) { if (kevent(loop->backend_fd, events, nevents, NULL, 0, NULL)) abort(); nevents = 0; } } if ((w->events & UV__POLLOUT) == 0 && (w->pevents & UV__POLLOUT) != 0) { EV_SET(events + nevents, w->fd, EVFILT_WRITE, EV_ADD, 0, 0, 0); if (++nevents == ARRAY_SIZE(events)) { if (kevent(loop->backend_fd, events, nevents, NULL, 0, NULL)) abort(); nevents = 0; } } w->events = w->pevents; } assert(timeout >= -1); base = loop->time; count = 48; /* Benchmarks suggest this gives the best throughput. */ for (;; nevents = 0) { if (timeout != -1) { spec.tv_sec = timeout / 1000; spec.tv_nsec = (timeout % 1000) * 1000000; } nfds = kevent(loop->backend_fd, events, nevents, events, ARRAY_SIZE(events), timeout == -1 ? NULL : &spec); /* Update loop->time unconditionally. It's tempting to skip the update when * timeout == 0 (i.e. non-blocking poll) but there is no guarantee that the * operating system didn't reschedule our process while in the syscall. */ SAVE_ERRNO(uv__update_time(loop)); if (nfds == 0) { assert(timeout != -1); return; } if (nfds == -1) { if (errno != EINTR) abort(); if (timeout == 0) return; if (timeout == -1) continue; /* Interrupted by a signal. Update timeout and poll again. */ goto update_timeout; } nevents = 0; for (i = 0; i < nfds; i++) { ev = events + i; fd = ev->ident; w = loop->watchers[fd]; if (w == NULL) { /* File descriptor that we've stopped watching, disarm it. */ /* TODO batch up */ struct kevent events[1]; EV_SET(events + 0, fd, ev->filter, EV_DELETE, 0, 0, 0); if (kevent(loop->backend_fd, events, 1, NULL, 0, NULL)) if (errno != EBADF && errno != ENOENT) abort(); continue; } if (ev->filter == EVFILT_VNODE) { assert(w->events == UV__POLLIN); assert(w->pevents == UV__POLLIN); w->cb(loop, w, ev->fflags); /* XXX always uv__fs_event() */ nevents++; continue; } revents = 0; if (ev->filter == EVFILT_READ) { if (w->events & UV__POLLIN) { revents |= UV__POLLIN; w->rcount = ev->data; } else { /* TODO batch up */ struct kevent events[1]; EV_SET(events + 0, fd, ev->filter, EV_DELETE, 0, 0, 0); if (kevent(loop->backend_fd, events, 1, NULL, 0, NULL)) if (errno != ENOENT) abort(); } } if (ev->filter == EVFILT_WRITE) { if (w->events & UV__POLLOUT) { revents |= UV__POLLOUT; w->wcount = ev->data; } else { /* TODO batch up */ struct kevent events[1]; EV_SET(events + 0, fd, ev->filter, EV_DELETE, 0, 0, 0); if (kevent(loop->backend_fd, events, 1, NULL, 0, NULL)) if (errno != ENOENT) abort(); } } if (ev->flags & EV_ERROR) revents |= UV__POLLERR; if (revents == 0) continue; w->cb(loop, w, revents); nevents++; } if (nevents != 0) { if (nfds == ARRAY_SIZE(events) && --count != 0) { /* Poll for more events but don't block this time. */ timeout = 0; continue; } return; } if (timeout == 0) return; if (timeout == -1) continue; update_timeout: assert(timeout > 0); diff = loop->time - base; if (diff >= (uint64_t) timeout) return; timeout -= diff; } }
/* execvp is marked __WATCHOS_PROHIBITED __TVOS_PROHIBITED, so must be * avoided. Since this isn't called on those targets, the function * doesn't even need to be defined for them. */ static void uv__process_child_init(const uv_process_options_t* options, int stdio_count, int (*pipes)[2], int error_fd) { sigset_t set; int close_fd; int use_fd; int err; int fd; int n; #if defined(__linux__) || defined(__FreeBSD__) int r; int i; int cpumask_size; uv__cpu_set_t cpuset; #endif if (options->flags & UV_PROCESS_DETACHED) setsid(); /* First duplicate low numbered fds, since it's not safe to duplicate them, * they could get replaced. Example: swapping stdout and stderr; without * this fd 2 (stderr) would be duplicated into fd 1, thus making both * stdout and stderr go to the same fd, which was not the intention. */ for (fd = 0; fd < stdio_count; fd++) { use_fd = pipes[fd][1]; if (use_fd < 0 || use_fd >= fd) continue; pipes[fd][1] = fcntl(use_fd, F_DUPFD, stdio_count); if (pipes[fd][1] == -1) { uv__write_int(error_fd, UV__ERR(errno)); _exit(127); } } for (fd = 0; fd < stdio_count; fd++) { close_fd = pipes[fd][0]; use_fd = pipes[fd][1]; if (use_fd < 0) { if (fd >= 3) continue; else { /* redirect stdin, stdout and stderr to /dev/null even if UV_IGNORE is * set */ use_fd = open("/dev/null", fd == 0 ? O_RDONLY : O_RDWR); close_fd = use_fd; if (use_fd == -1) { uv__write_int(error_fd, UV__ERR(errno)); _exit(127); } } } if (fd == use_fd) uv__cloexec_fcntl(use_fd, 0); else fd = dup2(use_fd, fd); if (fd == -1) { uv__write_int(error_fd, UV__ERR(errno)); _exit(127); } if (fd <= 2) uv__nonblock_fcntl(fd, 0); if (close_fd >= stdio_count) uv__close(close_fd); } for (fd = 0; fd < stdio_count; fd++) { use_fd = pipes[fd][1]; if (use_fd >= stdio_count) uv__close(use_fd); } if (options->cwd != NULL && chdir(options->cwd)) { uv__write_int(error_fd, UV__ERR(errno)); _exit(127); } if (options->flags & (UV_PROCESS_SETUID | UV_PROCESS_SETGID)) { /* When dropping privileges from root, the `setgroups` call will * remove any extraneous groups. If we don't call this, then * even though our uid has dropped, we may still have groups * that enable us to do super-user things. This will fail if we * aren't root, so don't bother checking the return value, this * is just done as an optimistic privilege dropping function. */ SAVE_ERRNO(setgroups(0, NULL)); } if ((options->flags & UV_PROCESS_SETGID) && setgid(options->gid)) { uv__write_int(error_fd, UV__ERR(errno)); _exit(127); } if ((options->flags & UV_PROCESS_SETUID) && setuid(options->uid)) { uv__write_int(error_fd, UV__ERR(errno)); _exit(127); } #if defined(__linux__) || defined(__FreeBSD__) if (options->cpumask != NULL) { cpumask_size = uv_cpumask_size(); assert(options->cpumask_size >= (size_t)cpumask_size); CPU_ZERO(&cpuset); for (i = 0; i < cpumask_size; ++i) { if (options->cpumask[i]) { CPU_SET(i, &cpuset); } } r = -pthread_setaffinity_np(pthread_self(), sizeof(cpuset), &cpuset); if (r != 0) { uv__write_int(error_fd, r); _exit(127); } } #endif if (options->env != NULL) { environ = options->env; } /* Reset signal disposition. Use a hard-coded limit because NSIG * is not fixed on Linux: it's either 32, 34 or 64, depending on * whether RT signals are enabled. We are not allowed to touch * RT signal handlers, glibc uses them internally. */ for (n = 1; n < 32; n += 1) { if (n == SIGKILL || n == SIGSTOP) continue; /* Can't be changed. */ if (SIG_ERR != signal(n, SIG_DFL)) continue; uv__write_int(error_fd, UV__ERR(errno)); _exit(127); } /* Reset signal mask. */ sigemptyset(&set); err = pthread_sigmask(SIG_SETMASK, &set, NULL); if (err != 0) { uv__write_int(error_fd, UV__ERR(err)); _exit(127); } execvp(options->file, options->args); uv__write_int(error_fd, UV__ERR(errno)); _exit(127); }
static void invokeArrayWithObjects_(JNIEnv* env, jlong ctxAddress, jbyteArray paramBuffer, jint objectCount, jint* infoBuffer, jobject* objectBuffer, void* retval) { Function* ctx = (Function *) j2p(ctxAddress); jbyte *tmpBuffer = NULL; void **ffiArgs = NULL; Array *arrays = NULL; unsigned int i, arrayCount = 0, paramBytes = 0; arrays = alloca(objectCount * sizeof(Array)); #if defined(USE_RAW) paramBytes = ctx->rawParameterSize; #else paramBytes = ctx->cif.nargs * PARAM_SIZE; #endif tmpBuffer = alloca(paramBytes); (*env)->GetByteArrayRegion(env, paramBuffer, 0, paramBytes, tmpBuffer); #ifndef USE_RAW ffiArgs = alloca(ctx->cif.nargs * sizeof(void *)); for (i = 0; i < (unsigned int) ctx->cif.nargs; ++i) { ffiArgs[i] = &tmpBuffer[i * PARAM_SIZE]; } #endif for (i = 0; i < (unsigned int) objectCount; ++i) { int type = infoBuffer[i * 3]; jsize offset = infoBuffer[(i * 3) + 1]; jsize length = infoBuffer[(i * 3) + 2]; jobject object = objectBuffer[i]; int idx = (type & com_kenai_jffi_ObjectBuffer_INDEX_MASK) >> com_kenai_jffi_ObjectBuffer_INDEX_SHIFT; void* ptr; switch (type & com_kenai_jffi_ObjectBuffer_TYPE_MASK & ~com_kenai_jffi_ObjectBuffer_PRIM_MASK) { case com_kenai_jffi_ObjectBuffer_ARRAY: if (unlikely(object == NULL)) { throwException(env, NullPointer, "null object for parameter %d", idx); goto cleanup; } else if (unlikely((type & com_kenai_jffi_ObjectBuffer_PINNED) != 0)) { ptr = jffi_getArrayCritical(env, object, offset, length, type, &arrays[arrayCount]); if (unlikely(ptr == NULL)) { goto cleanup; } } else if (true && likely(length < MAX_STACK_ARRAY)) { ptr = alloca(jffi_arraySize(length + 1, type)); if (unlikely(jffi_getArrayBuffer(env, object, offset, length, type, &arrays[arrayCount], ptr) == NULL)) { goto cleanup; } } else { ptr = jffi_getArrayHeap(env, object, offset, length, type, &arrays[arrayCount]); if (unlikely(ptr == NULL)) { goto cleanup; } } ++arrayCount; break; case com_kenai_jffi_ObjectBuffer_BUFFER: ptr = (*env)->GetDirectBufferAddress(env, object); if (unlikely(ptr == NULL)) { throwException(env, NullPointer, "Could not get direct Buffer address"); goto cleanup; } ptr = ((char *) ptr + offset); break; case com_kenai_jffi_ObjectBuffer_JNI: switch (type & com_kenai_jffi_ObjectBuffer_TYPE_MASK) { case com_kenai_jffi_ObjectBuffer_JNIENV: ptr = env; break; case com_kenai_jffi_ObjectBuffer_JNIOBJECT: ptr = (void *) object; break; default: throwException(env, IllegalArgument, "Unsupported object type: %#x", type & com_kenai_jffi_ObjectBuffer_TYPE_MASK); goto cleanup; } break; default: throwException(env, IllegalArgument, "Unsupported object type: %#x", type & com_kenai_jffi_ObjectBuffer_TYPE_MASK); goto cleanup; } #if defined(USE_RAW) *((void **)(tmpBuffer + ctx->rawParamOffsets[idx])) = ptr; #else if (unlikely(ctx->cif.arg_types[idx]->type == FFI_TYPE_STRUCT)) { ffiArgs[idx] = ptr; } else { *((void **) ffiArgs[idx]) = ptr; } #endif } #if defined(USE_RAW) // // Special case for struct return values - unroll into a ptr array and // use ffi_call, since ffi_raw_call with struct return values is undocumented. // if (unlikely(ctx->cif.rtype->type == FFI_TYPE_STRUCT)) { ffiArgs = alloca(ctx->cif.nargs * sizeof(void *)); for (i = 0; i < ctx->cif.nargs; ++i) { ffiArgs[i] = (tmpBuffer + ctx->rawParamOffsets[i]); } ffi_call(&ctx->cif, FFI_FN(ctx->function), retval, ffiArgs); } else { ffi_raw_call(&ctx->cif, FFI_FN(ctx->function), retval, (ffi_raw *) tmpBuffer); } #else ffi_call(&ctx->cif, FFI_FN(ctx->function), retval, ffiArgs); #endif SAVE_ERRNO(ctx); cleanup: /* Release any array backing memory */ for (i = 0; i < arrayCount; ++i) { if (arrays[i].release != NULL) { //printf("releasing array=%p\n", arrays[i].elems); (*arrays[i].release)(env, &arrays[i]); } } }
void uv__io_poll(uv_loop_t* loop, int timeout) { struct port_event events[1024]; struct port_event* pe; struct timespec spec; QUEUE* q; uv__io_t* w; uint64_t base; uint64_t diff; unsigned int nfds; unsigned int i; int saved_errno; int nevents; int count; int fd; if (loop->nfds == 0) { assert(QUEUE_EMPTY(&loop->watcher_queue)); return; } while (!QUEUE_EMPTY(&loop->watcher_queue)) { q = QUEUE_HEAD(&loop->watcher_queue); QUEUE_REMOVE(q); QUEUE_INIT(q); w = QUEUE_DATA(q, uv__io_t, watcher_queue); assert(w->pevents != 0); if (port_associate(loop->backend_fd, PORT_SOURCE_FD, w->fd, w->pevents, 0)) abort(); w->events = w->pevents; } assert(timeout >= -1); base = loop->time; count = 48; /* Benchmarks suggest this gives the best throughput. */ for (;;) { if (timeout != -1) { spec.tv_sec = timeout / 1000; spec.tv_nsec = (timeout % 1000) * 1000000; } /* Work around a kernel bug where nfds is not updated. */ events[0].portev_source = 0; nfds = 1; saved_errno = 0; if (port_getn(loop->backend_fd, events, ARRAY_SIZE(events), &nfds, timeout == -1 ? NULL : &spec)) { /* Work around another kernel bug: port_getn() may return events even * on error. */ if (errno == EINTR || errno == ETIME) saved_errno = errno; else abort(); } /* Update loop->time unconditionally. It's tempting to skip the update when * timeout == 0 (i.e. non-blocking poll) but there is no guarantee that the * operating system didn't reschedule our process while in the syscall. */ SAVE_ERRNO(uv__update_time(loop)); if (events[0].portev_source == 0) { if (timeout == 0) return; if (timeout == -1) continue; goto update_timeout; } if (nfds == 0) { assert(timeout != -1); return; } nevents = 0; for (i = 0; i < nfds; i++) { pe = events + i; fd = pe->portev_object; assert(fd >= 0); assert((unsigned) fd < loop->nwatchers); w = loop->watchers[fd]; /* File descriptor that we've stopped watching, ignore. */ if (w == NULL) continue; w->cb(loop, w, pe->portev_events); nevents++; if (w != loop->watchers[fd]) continue; /* Disabled by callback. */ /* Events Ports operates in oneshot mode, rearm timer on next run. */ if (w->pevents != 0 && QUEUE_EMPTY(&w->watcher_queue)) QUEUE_INSERT_TAIL(&loop->watcher_queue, &w->watcher_queue); } if (nevents != 0) { if (nfds == ARRAY_SIZE(events) && --count != 0) { /* Poll for more events but don't block this time. */ timeout = 0; continue; } return; } if (saved_errno == ETIME) { assert(timeout != -1); return; } if (timeout == 0) return; if (timeout == -1) continue; update_timeout: assert(timeout > 0); diff = loop->time - base; if (diff >= (uint64_t) timeout) return; timeout -= diff; } }
void uv__server_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) { static int use_emfile_trick = -1; uv_stream_t* stream; int fd; int r; stream = container_of(w, uv_stream_t, io_watcher); assert(events == UV__POLLIN); assert(stream->accepted_fd == -1); assert(!(stream->flags & UV_CLOSING)); if (stream->accepted_fd == -1) uv__io_start(stream->loop, &stream->io_watcher, UV__POLLIN); /* connection_cb can close the server socket while we're * in the loop so check it on each iteration. */ while (uv__stream_fd(stream) != -1) { assert(stream->accepted_fd == -1); fd = uv__accept(uv__stream_fd(stream)); if (fd == -1) { switch (errno) { #if EWOULDBLOCK != EAGAIN case EWOULDBLOCK: #endif case EAGAIN: return; /* Not an error. */ case ECONNABORTED: continue; /* Ignore. */ case EMFILE: case ENFILE: if (use_emfile_trick == -1) { const char* val = getenv("UV_ACCEPT_EMFILE_TRICK"); use_emfile_trick = (val == NULL || atoi(val) != 0); } if (use_emfile_trick) { SAVE_ERRNO(r = uv__emfile_trick(loop, uv__stream_fd(stream))); if (r == 0) continue; } /* Fall through. */ default: uv__set_sys_error(loop, errno); stream->connection_cb(stream, -1); continue; } } stream->accepted_fd = fd; stream->connection_cb(stream, 0); if (stream->accepted_fd != -1) { /* The user hasn't yet accepted called uv_accept() */ uv__io_stop(loop, &stream->io_watcher, UV__POLLIN); return; } if (stream->type == UV_TCP && (stream->flags & UV_TCP_SINGLE_ACCEPT)) { /* Give other processes a chance to accept connections. */ struct timespec timeout = { 0, 1 }; nanosleep(&timeout, NULL); } } }
void uv__io_poll(uv_loop_t* loop, int timeout) { /* A bug in kernels < 2.6.37 makes timeouts larger than ~30 minutes * effectively infinite on 32 bits architectures. To avoid blocking * indefinitely, we cap the timeout and poll again if necessary. * * Note that "30 minutes" is a simplification because it depends on * the value of CONFIG_HZ. The magic constant assumes CONFIG_HZ=1200, * that being the largest value I have seen in the wild (and only once.) */ static const int max_safe_timeout = 1789569; static int no_epoll_pwait; static int no_epoll_wait; struct uv__epoll_event events[1024]; struct uv__epoll_event* pe; struct uv__epoll_event e; int real_timeout; QUEUE* q; uv__io_t* w; sigset_t sigset; uint64_t sigmask; uint64_t base; int nevents; int count; int nfds; int fd; int op; int i; if (loop->nfds == 0) { assert(QUEUE_EMPTY(&loop->watcher_queue)); return; } while (!QUEUE_EMPTY(&loop->watcher_queue)) { q = QUEUE_HEAD(&loop->watcher_queue); QUEUE_REMOVE(q); QUEUE_INIT(q); w = QUEUE_DATA(q, uv__io_t, watcher_queue); assert(w->pevents != 0); assert(w->fd >= 0); assert(w->fd < (int) loop->nwatchers); e.events = w->pevents; e.data = w->fd; if (w->events == 0) op = UV__EPOLL_CTL_ADD; else op = UV__EPOLL_CTL_MOD; /* XXX Future optimization: do EPOLL_CTL_MOD lazily if we stop watching * events, skip the syscall and squelch the events after epoll_wait(). */ if (uv__epoll_ctl(loop->backend_fd, op, w->fd, &e)) { if (errno != EEXIST) abort(); assert(op == UV__EPOLL_CTL_ADD); /* We've reactivated a file descriptor that's been watched before. */ if (uv__epoll_ctl(loop->backend_fd, UV__EPOLL_CTL_MOD, w->fd, &e)) abort(); } w->events = w->pevents; } sigmask = 0; if (loop->flags & UV_LOOP_BLOCK_SIGPROF) { sigemptyset(&sigset); sigaddset(&sigset, SIGPROF); sigmask |= 1 << (SIGPROF - 1); } assert(timeout >= -1); base = loop->time; count = 48; /* Benchmarks suggest this gives the best throughput. */ real_timeout = timeout; for (;;) { /* See the comment for max_safe_timeout for an explanation of why * this is necessary. Executive summary: kernel bug workaround. */ if (sizeof(int32_t) == sizeof(long) && timeout >= max_safe_timeout) timeout = max_safe_timeout; if (sigmask != 0 && no_epoll_pwait != 0) if (pthread_sigmask(SIG_BLOCK, &sigset, NULL)) abort(); if (no_epoll_wait != 0 || (sigmask != 0 && no_epoll_pwait == 0)) { nfds = uv__epoll_pwait(loop->backend_fd, events, ARRAY_SIZE(events), timeout, sigmask); if (nfds == -1 && errno == ENOSYS) no_epoll_pwait = 1; } else { nfds = uv__epoll_wait(loop->backend_fd, events, ARRAY_SIZE(events), timeout); if (nfds == -1 && errno == ENOSYS) no_epoll_wait = 1; } if (sigmask != 0 && no_epoll_pwait != 0) if (pthread_sigmask(SIG_UNBLOCK, &sigset, NULL)) abort(); /* Update loop->time unconditionally. It's tempting to skip the update when * timeout == 0 (i.e. non-blocking poll) but there is no guarantee that the * operating system didn't reschedule our process while in the syscall. */ SAVE_ERRNO(uv__update_time(loop)); if (nfds == 0) { assert(timeout != -1); timeout = real_timeout - timeout; if (timeout > 0) continue; return; } if (nfds == -1) { if (errno == ENOSYS) { /* epoll_wait() or epoll_pwait() failed, try the other system call. */ assert(no_epoll_wait == 0 || no_epoll_pwait == 0); continue; } if (errno != EINTR) abort(); if (timeout == -1) continue; if (timeout == 0) return; /* Interrupted by a signal. Update timeout and poll again. */ goto update_timeout; } nevents = 0; assert(loop->watchers != NULL); loop->watchers[loop->nwatchers] = (void*) events; loop->watchers[loop->nwatchers + 1] = (void*) (uintptr_t) nfds; for (i = 0; i < nfds; i++) { pe = events + i; fd = pe->data; /* Skip invalidated events, see uv__platform_invalidate_fd */ if (fd == -1) continue; assert(fd >= 0); assert((unsigned) fd < loop->nwatchers); w = loop->watchers[fd]; if (w == NULL) { /* File descriptor that we've stopped watching, disarm it. * * Ignore all errors because we may be racing with another thread * when the file descriptor is closed. */ uv__epoll_ctl(loop->backend_fd, UV__EPOLL_CTL_DEL, fd, pe); continue; } /* Give users only events they're interested in. Prevents spurious * callbacks when previous callback invocation in this loop has stopped * the current watcher. Also, filters out events that users has not * requested us to watch. */ pe->events &= w->pevents | UV__POLLERR | UV__POLLHUP; /* Work around an epoll quirk where it sometimes reports just the * EPOLLERR or EPOLLHUP event. In order to force the event loop to * move forward, we merge in the read/write events that the watcher * is interested in; uv__read() and uv__write() will then deal with * the error or hangup in the usual fashion. * * Note to self: happens when epoll reports EPOLLIN|EPOLLHUP, the user * reads the available data, calls uv_read_stop(), then sometime later * calls uv_read_start() again. By then, libuv has forgotten about the * hangup and the kernel won't report EPOLLIN again because there's * nothing left to read. If anything, libuv is to blame here. The * current hack is just a quick bandaid; to properly fix it, libuv * needs to remember the error/hangup event. We should get that for * free when we switch over to edge-triggered I/O. */ if (pe->events == UV__EPOLLERR || pe->events == UV__EPOLLHUP) pe->events |= w->pevents & (UV__EPOLLIN | UV__EPOLLOUT); if (pe->events != 0) { w->cb(loop, w, pe->events); nevents++; } } loop->watchers[loop->nwatchers] = NULL; loop->watchers[loop->nwatchers + 1] = NULL; if (nevents != 0) { if (nfds == ARRAY_SIZE(events) && --count != 0) { /* Poll for more events but don't block this time. */ timeout = 0; continue; } return; } if (timeout == 0) return; if (timeout == -1) continue; update_timeout: assert(timeout > 0); real_timeout -= (loop->time - base); if (real_timeout <= 0) return; timeout = real_timeout; } }
void uv__io_poll(uv_loop_t* loop, int timeout) { struct uv__epoll_event events[1024]; struct uv__epoll_event* pe; struct uv__epoll_event e; ngx_queue_t* q; uv__io_t* w; uint64_t base; uint64_t diff; int nevents; int count; int nfds; int fd; int op; int i; if (loop->nfds == 0) { assert(ngx_queue_empty(&loop->watcher_queue)); return; } while (!ngx_queue_empty(&loop->watcher_queue)) { q = ngx_queue_head(&loop->watcher_queue); ngx_queue_remove(q); ngx_queue_init(q); w = ngx_queue_data(q, uv__io_t, watcher_queue); assert(w->pevents != 0); assert(w->fd >= 0); assert(w->fd < (int) loop->nwatchers); e.events = w->pevents; e.data = w->fd; if (w->events == 0) op = UV__EPOLL_CTL_ADD; else op = UV__EPOLL_CTL_MOD; /* XXX Future optimization: do EPOLL_CTL_MOD lazily if we stop watching * events, skip the syscall and squelch the events after epoll_wait(). */ if (uv__epoll_ctl(loop->backend_fd, op, w->fd, &e)) { if (errno != EEXIST) abort(); assert(op == UV__EPOLL_CTL_ADD); /* We've reactivated a file descriptor that's been watched before. */ if (uv__epoll_ctl(loop->backend_fd, UV__EPOLL_CTL_MOD, w->fd, &e)) abort(); } w->events = w->pevents; } assert(timeout >= -1); base = loop->time; count = 48; /* Benchmarks suggest this gives the best throughput. */ for (;;) { nfds = uv__epoll_wait(loop->backend_fd, events, ARRAY_SIZE(events), timeout); /* Update loop->time unconditionally. It's tempting to skip the update when * timeout == 0 (i.e. non-blocking poll) but there is no guarantee that the * operating system didn't reschedule our process while in the syscall. */ SAVE_ERRNO(uv__update_time(loop)); if (nfds == 0) { assert(timeout != -1); return; } if (nfds == -1) { if (errno != EINTR) abort(); if (timeout == -1) continue; if (timeout == 0) return; /* Interrupted by a signal. Update timeout and poll again. */ goto update_timeout; } nevents = 0; assert(loop->watchers != NULL); loop->watchers[loop->nwatchers] = (void*) events; loop->watchers[loop->nwatchers + 1] = (void*) (uintptr_t) nfds; for (i = 0; i < nfds; i++) { pe = events + i; fd = pe->data; /* Skip invalidated events, see uv__platform_invalidate_fd */ if (fd == -1) continue; assert(fd >= 0); assert((unsigned) fd < loop->nwatchers); w = loop->watchers[fd]; if (w == NULL) { /* File descriptor that we've stopped watching, disarm it. * * Ignore all errors because we may be racing with another thread * when the file descriptor is closed. */ uv__epoll_ctl(loop->backend_fd, UV__EPOLL_CTL_DEL, fd, pe); continue; } /* Give users only events they're interested in. Prevents spurious * callbacks when previous callback invocation in this loop has stopped * the current watcher. Also, filters out events that users has not * requested us to watch. */ pe->events &= w->pevents | UV__POLLERR | UV__POLLHUP; /* Work around an epoll quirk where it sometimes reports just the * EPOLLERR or EPOLLHUP event. In order to force the event loop to * move forward, we merge in the read/write events that the watcher * is interested in; uv__read() and uv__write() will then deal with * the error or hangup in the usual fashion. * * Note to self: happens when epoll reports EPOLLIN|EPOLLHUP, the user * reads the available data, calls uv_read_stop(), then sometime later * calls uv_read_start() again. By then, libuv has forgotten about the * hangup and the kernel won't report EPOLLIN again because there's * nothing left to read. If anything, libuv is to blame here. The * current hack is just a quick bandaid; to properly fix it, libuv * needs to remember the error/hangup event. We should get that for * free when we switch over to edge-triggered I/O. */ if (pe->events == UV__EPOLLERR || pe->events == UV__EPOLLHUP) pe->events |= w->pevents & (UV__EPOLLIN | UV__EPOLLOUT); if (pe->events != 0) { w->cb(loop, w, pe->events); nevents++; } } loop->watchers[loop->nwatchers] = NULL; loop->watchers[loop->nwatchers + 1] = NULL; if (nevents != 0) { if (nfds == ARRAY_SIZE(events) && --count != 0) { /* Poll for more events but don't block this time. */ timeout = 0; continue; } return; } if (timeout == 0) return; if (timeout == -1) continue; update_timeout: assert(timeout > 0); diff = loop->time - base; if (diff >= (uint64_t) timeout) return; timeout -= diff; } }
int uv__stream_try_select(uv_stream_t* stream, int fd) { /* * kqueue doesn't work with some files from /dev mount on osx. * select(2) in separate thread for those fds */ struct kevent filter[1]; struct kevent events[1]; struct timespec timeout; uv__stream_select_t* s; int fds[2]; int ret; int kq; kq = kqueue(); if (kq == -1) { fprintf(stderr, "(libuv) Failed to create kqueue (%d)\n", errno); return uv__set_sys_error(stream->loop, errno); } EV_SET(&filter[0], fd, EVFILT_READ, EV_ADD | EV_ENABLE, 0, 0, 0); /* Use small timeout, because we only want to capture EINVALs */ timeout.tv_sec = 0; timeout.tv_nsec = 1; ret = kevent(kq, filter, 1, events, 1, &timeout); SAVE_ERRNO(close(kq)); if (ret == -1) return uv__set_sys_error(stream->loop, errno); if ((events[0].flags & EV_ERROR) == 0 || events[0].data != EINVAL) return 0; /* At this point we definitely know that this fd won't work with kqueue */ s = malloc(sizeof(*s)); if (s == NULL) return uv__set_artificial_error(stream->loop, UV_ENOMEM); s->fd = fd; if (uv_async_init(stream->loop, &s->async, uv__stream_osx_select_cb)) { SAVE_ERRNO(free(s)); return uv__set_sys_error(stream->loop, errno); } s->async.flags |= UV__HANDLE_INTERNAL; uv__handle_unref(&s->async); if (uv_sem_init(&s->sem, 0)) goto fatal1; if (uv_mutex_init(&s->mutex)) goto fatal2; /* Create fds for io watcher and to interrupt the select() loop. */ if (socketpair(AF_UNIX, SOCK_STREAM, 0, fds)) goto fatal3; s->fake_fd = fds[0]; s->int_fd = fds[1]; if (uv_thread_create(&s->thread, uv__stream_osx_select, stream)) goto fatal4; s->stream = stream; stream->select = s; return 0; fatal4: close(s->fake_fd); close(s->int_fd); s->fake_fd = -1; s->int_fd = -1; fatal3: uv_mutex_destroy(&s->mutex); fatal2: uv_sem_destroy(&s->sem); fatal1: uv_close((uv_handle_t*) &s->async, uv__stream_osx_cb_close); return uv__set_sys_error(stream->loop, errno); }
static void uv__process_child_init(const uv_process_options_t* options, int stdio_count, int (*pipes)[2], int error_fd) { int close_fd; int use_fd; int fd; if (options->flags & UV_PROCESS_DETACHED) setsid(); for (fd = 0; fd < stdio_count; fd++) { close_fd = pipes[fd][0]; use_fd = pipes[fd][1]; if (use_fd < 0) { if (fd >= 3) continue; else { /* redirect stdin, stdout and stderr to /dev/null even if UV_IGNORE is * set */ use_fd = open("/dev/null", fd == 0 ? O_RDONLY : O_RDWR); close_fd = use_fd; if (use_fd == -1) { uv__write_int(error_fd, -errno); perror("failed to open stdio"); _exit(127); } } } if (close_fd != -1) { /* Can't call uv__close, since that might fail an assertion if close_fd=0 */ close(close_fd); } if (fd == use_fd) uv__cloexec(use_fd, 0); else dup2(use_fd, fd); if (fd <= 2) uv__nonblock(fd, 0); } for (fd = 0; fd < stdio_count; fd++) { use_fd = pipes[fd][1]; if (use_fd >= 0 && fd != use_fd) close(use_fd); } if (options->cwd != NULL && chdir(options->cwd)) { uv__write_int(error_fd, -errno); perror("chdir()"); _exit(127); } if (options->flags & (UV_PROCESS_SETUID | UV_PROCESS_SETGID)) { /* When dropping privileges from root, the `setgroups` call will * remove any extraneous groups. If we don't call this, then * even though our uid has dropped, we may still have groups * that enable us to do super-user things. This will fail if we * aren't root, so don't bother checking the return value, this * is just done as an optimistic privilege dropping function. */ SAVE_ERRNO(setgroups(0, NULL)); } if ((options->flags & UV_PROCESS_SETGID) && setgid(options->gid)) { uv__write_int(error_fd, -errno); perror("setgid()"); _exit(127); } if ((options->flags & UV_PROCESS_SETUID) && setuid(options->uid)) { uv__write_int(error_fd, -errno); perror("setuid()"); _exit(127); } if (options->env != NULL) { environ = options->env; } execvp(options->file, options->args); uv__write_int(error_fd, -errno); perror("execvp()"); _exit(127); }
int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) { unsigned int ticks = (unsigned int)sysconf(_SC_CLK_TCK), multiplier = ((uint64_t)1000L / ticks), cpuspeed, maxcpus, cur = 0; uv_cpu_info_t* cpu_info; const char* maxcpus_key; const char* cptimes_key; char model[512]; long* cp_times; int numcpus; size_t size; int i; #if defined(__DragonFly__) /* This is not quite correct but DragonFlyBSD doesn't seem to have anything * comparable to kern.smp.maxcpus or kern.cp_times (kern.cp_time is a total, * not per CPU). At least this stops uv_cpu_info() from failing completely. */ maxcpus_key = "hw.ncpu"; cptimes_key = "kern.cp_time"; #else maxcpus_key = "kern.smp.maxcpus"; cptimes_key = "kern.cp_times"; #endif size = sizeof(model); if (sysctlbyname("hw.model", &model, &size, NULL, 0)) return -errno; size = sizeof(numcpus); if (sysctlbyname("hw.ncpu", &numcpus, &size, NULL, 0)) return -errno; *cpu_infos = malloc(numcpus * sizeof(**cpu_infos)); if (!(*cpu_infos)) return -ENOMEM; *count = numcpus; size = sizeof(cpuspeed); if (sysctlbyname("hw.clockrate", &cpuspeed, &size, NULL, 0)) { SAVE_ERRNO(free(*cpu_infos)); return -errno; } /* kern.cp_times on FreeBSD i386 gives an array up to maxcpus instead of * ncpu. */ size = sizeof(maxcpus); if (sysctlbyname(maxcpus_key, &maxcpus, &size, NULL, 0)) { SAVE_ERRNO(free(*cpu_infos)); return -errno; } size = maxcpus * CPUSTATES * sizeof(long); cp_times = malloc(size); if (cp_times == NULL) { free(*cpu_infos); return -ENOMEM; } if (sysctlbyname(cptimes_key, cp_times, &size, NULL, 0)) { SAVE_ERRNO(free(cp_times)); SAVE_ERRNO(free(*cpu_infos)); return -errno; } for (i = 0; i < numcpus; i++) { cpu_info = &(*cpu_infos)[i]; cpu_info->cpu_times.user = (uint64_t)(cp_times[CP_USER+cur]) * multiplier; cpu_info->cpu_times.nice = (uint64_t)(cp_times[CP_NICE+cur]) * multiplier; cpu_info->cpu_times.sys = (uint64_t)(cp_times[CP_SYS+cur]) * multiplier; cpu_info->cpu_times.idle = (uint64_t)(cp_times[CP_IDLE+cur]) * multiplier; cpu_info->cpu_times.irq = (uint64_t)(cp_times[CP_INTR+cur]) * multiplier; cpu_info->model = strdup(model); cpu_info->speed = cpuspeed; cur+=CPUSTATES; } free(cp_times); return 0; }
void uv__io_poll(uv_loop_t* loop, int timeout) { struct kevent events[1024]; struct kevent* ev; struct timespec spec; unsigned int nevents; unsigned int revents; QUEUE* q; uv__io_t* w; sigset_t* pset; sigset_t set; uint64_t base; uint64_t diff; int have_signals; int filter; int fflags; int count; int nfds; int fd; int op; int i; if (loop->nfds == 0) { assert(QUEUE_EMPTY(&loop->watcher_queue)); return; } nevents = 0; while (!QUEUE_EMPTY(&loop->watcher_queue)) { q = QUEUE_HEAD(&loop->watcher_queue); QUEUE_REMOVE(q); QUEUE_INIT(q); w = QUEUE_DATA(q, uv__io_t, watcher_queue); assert(w->pevents != 0); assert(w->fd >= 0); assert(w->fd < (int) loop->nwatchers); if ((w->events & POLLIN) == 0 && (w->pevents & POLLIN) != 0) { filter = EVFILT_READ; fflags = 0; op = EV_ADD; if (w->cb == uv__fs_event) { filter = EVFILT_VNODE; fflags = NOTE_ATTRIB | NOTE_WRITE | NOTE_RENAME | NOTE_DELETE | NOTE_EXTEND | NOTE_REVOKE; op = EV_ADD | EV_ONESHOT; /* Stop the event from firing repeatedly. */ } EV_SET(events + nevents, w->fd, filter, op, fflags, 0, 0); if (++nevents == ARRAY_SIZE(events)) { if (kevent(loop->backend_fd, events, nevents, NULL, 0, NULL)) abort(); nevents = 0; } } if ((w->events & POLLOUT) == 0 && (w->pevents & POLLOUT) != 0) { EV_SET(events + nevents, w->fd, EVFILT_WRITE, EV_ADD, 0, 0, 0); if (++nevents == ARRAY_SIZE(events)) { if (kevent(loop->backend_fd, events, nevents, NULL, 0, NULL)) abort(); nevents = 0; } } w->events = w->pevents; } pset = NULL; if (loop->flags & UV_LOOP_BLOCK_SIGPROF) { pset = &set; sigemptyset(pset); sigaddset(pset, SIGPROF); } assert(timeout >= -1); base = loop->time; count = 48; /* Benchmarks suggest this gives the best throughput. */ for (;; nevents = 0) { if (timeout != -1) { spec.tv_sec = timeout / 1000; spec.tv_nsec = (timeout % 1000) * 1000000; } if (pset != NULL) pthread_sigmask(SIG_BLOCK, pset, NULL); nfds = kevent(loop->backend_fd, events, nevents, events, ARRAY_SIZE(events), timeout == -1 ? NULL : &spec); if (pset != NULL) pthread_sigmask(SIG_UNBLOCK, pset, NULL); /* Update loop->time unconditionally. It's tempting to skip the update when * timeout == 0 (i.e. non-blocking poll) but there is no guarantee that the * operating system didn't reschedule our process while in the syscall. */ SAVE_ERRNO(uv__update_time(loop)); if (nfds == 0) { assert(timeout != -1); return; } if (nfds == -1) { if (errno != EINTR) abort(); if (timeout == 0) return; if (timeout == -1) continue; /* Interrupted by a signal. Update timeout and poll again. */ goto update_timeout; } have_signals = 0; nevents = 0; assert(loop->watchers != NULL); loop->watchers[loop->nwatchers] = (void*) events; loop->watchers[loop->nwatchers + 1] = (void*) (uintptr_t) nfds; for (i = 0; i < nfds; i++) { ev = events + i; fd = ev->ident; /* Skip invalidated events, see uv__platform_invalidate_fd */ if (fd == -1) continue; w = loop->watchers[fd]; if (w == NULL) { /* File descriptor that we've stopped watching, disarm it. */ /* TODO batch up */ struct kevent events[1]; EV_SET(events + 0, fd, ev->filter, EV_DELETE, 0, 0, 0); if (kevent(loop->backend_fd, events, 1, NULL, 0, NULL)) if (errno != EBADF && errno != ENOENT) abort(); continue; } if (ev->filter == EVFILT_VNODE) { assert(w->events == POLLIN); assert(w->pevents == POLLIN); w->cb(loop, w, ev->fflags); /* XXX always uv__fs_event() */ nevents++; continue; } revents = 0; if (ev->filter == EVFILT_READ) { if (w->pevents & POLLIN) { revents |= POLLIN; w->rcount = ev->data; } else { /* TODO batch up */ struct kevent events[1]; EV_SET(events + 0, fd, ev->filter, EV_DELETE, 0, 0, 0); if (kevent(loop->backend_fd, events, 1, NULL, 0, NULL)) if (errno != ENOENT) abort(); } } if (ev->filter == EVFILT_WRITE) { if (w->pevents & POLLOUT) { revents |= POLLOUT; w->wcount = ev->data; } else { /* TODO batch up */ struct kevent events[1]; EV_SET(events + 0, fd, ev->filter, EV_DELETE, 0, 0, 0); if (kevent(loop->backend_fd, events, 1, NULL, 0, NULL)) if (errno != ENOENT) abort(); } } if (ev->flags & EV_ERROR) revents |= POLLERR; if ((ev->flags & EV_EOF) && (w->pevents & UV__POLLRDHUP)) revents |= UV__POLLRDHUP; if (revents == 0) continue; /* Run signal watchers last. This also affects child process watchers * because those are implemented in terms of signal watchers. */ if (w == &loop->signal_io_watcher) have_signals = 1; else w->cb(loop, w, revents); nevents++; } if (have_signals != 0) loop->signal_io_watcher.cb(loop, &loop->signal_io_watcher, POLLIN); loop->watchers[loop->nwatchers] = NULL; loop->watchers[loop->nwatchers + 1] = NULL; if (have_signals != 0) return; /* Event loop should cycle now so don't poll again. */ if (nevents != 0) { if (nfds == ARRAY_SIZE(events) && --count != 0) { /* Poll for more events but don't block this time. */ timeout = 0; continue; } return; } if (timeout == 0) return; if (timeout == -1) continue; update_timeout: assert(timeout > 0); diff = loop->time - base; if (diff >= (uint64_t) timeout) return; timeout -= diff; } }
void uv__io_poll(uv_loop_t* loop, int timeout) { struct pollfd pfd; struct pollfd* pe; QUEUE* q; uv__io_t* w; uint64_t base; uint64_t diff; int nevents; int count; int nfd; int i; if (loop->nfds == 0) { assert(QUEUE_EMPTY(&loop->watcher_queue)); return; } while (!QUEUE_EMPTY(&loop->watcher_queue)) { q = QUEUE_HEAD(&loop->watcher_queue); QUEUE_REMOVE(q); QUEUE_INIT(q); w = QUEUE_DATA(q, uv__io_t, watcher_queue); assert(w->pevents != 0); assert(w->fd >= 0); assert(w->fd < (int)loop->nwatchers); pfd.fd = w->fd; pfd.events = w->pevents; uv__add_pollfd(loop, &pfd); w->events = w->pevents; } assert(timeout >= -1); base = loop->time; count = 5; for (;;) { nfd = poll(loop->pollfds, loop->npollfds, timeout); SAVE_ERRNO(uv__update_time(loop)); if (nfd == 0) { assert(timeout != -1); return; } if (nfd == -1) { int err = get_errno(); if (err == EAGAIN ) { set_errno(0); } else if ( err != EINTR) { TDLOG("uv__io_poll abort for errno(%d)", err); ABORT(); } if (timeout == -1) { continue; } if (timeout == 0) { return; } goto update_timeout; } nevents = 0; for (i = 0; i < loop->npollfds; ++i) { pe = &loop->pollfds[i]; if (pe->fd >= 0) { if (pe->revents & (POLLIN | POLLOUT | POLLHUP)) { w = loop->watchers[pe->fd]; if (w == NULL) { uv__rem_pollfd(loop, pe); } else { w->cb(loop, w, pe->revents); ++nevents; } } } } if (nevents != 0) { if (--count != 0) { timeout = 0; continue; } return; } if (timeout == 0) { return; } if (timeout == -1) { continue; } update_timeout: assert(timeout > 0); diff = loop->time - base; if (diff >= (uint64_t)timeout) { return; } timeout -= diff; } }
static void uv__process_child_init(const uv_process_options_t* options, int stdio_count, int (*pipes)[2], int error_fd) { int close_fd; int use_fd; int fd; if (options->flags & UV_PROCESS_DETACHED) setsid(); /* First duplicate low numbered fds, since it's not safe to duplicate them, * they could get replaced. Example: swapping stdout and stderr; without * this fd 2 (stderr) would be duplicated into fd 1, thus making both * stdout and stderr go to the same fd, which was not the intention. */ for (fd = 0; fd < stdio_count; fd++) { use_fd = pipes[fd][1]; if (use_fd < 0 || use_fd >= fd) continue; pipes[fd][1] = fcntl(use_fd, F_DUPFD, stdio_count); if (pipes[fd][1] == -1) { uv__write_int(error_fd, -errno); _exit(127); } } for (fd = 0; fd < stdio_count; fd++) { close_fd = pipes[fd][0]; use_fd = pipes[fd][1]; if (use_fd < 0) { if (fd >= 3) continue; else { /* redirect stdin, stdout and stderr to /dev/null even if UV_IGNORE is * set */ use_fd = open("/dev/null", fd == 0 ? O_RDONLY : O_RDWR); close_fd = use_fd; if (use_fd == -1) { uv__write_int(error_fd, -errno); _exit(127); } } } if (fd == use_fd) uv__cloexec(use_fd, 0); else fd = dup2(use_fd, fd); if (fd == -1) { uv__write_int(error_fd, -errno); _exit(127); } if (fd <= 2) uv__nonblock(fd, 0); if (close_fd >= stdio_count) uv__close(close_fd); } for (fd = 0; fd < stdio_count; fd++) { use_fd = pipes[fd][1]; if (use_fd >= stdio_count) uv__close(use_fd); } if (options->cwd != NULL && chdir(options->cwd)) { uv__write_int(error_fd, -errno); _exit(127); } if (options->flags & (UV_PROCESS_SETUID | UV_PROCESS_SETGID)) { /* When dropping privileges from root, the `setgroups` call will * remove any extraneous groups. If we don't call this, then * even though our uid has dropped, we may still have groups * that enable us to do super-user things. This will fail if we * aren't root, so don't bother checking the return value, this * is just done as an optimistic privilege dropping function. */ SAVE_ERRNO(setgroups(0, NULL)); } if ((options->flags & UV_PROCESS_SETGID) && setgid(options->gid)) { uv__write_int(error_fd, -errno); _exit(127); } if ((options->flags & UV_PROCESS_SETUID) && setuid(options->uid)) { uv__write_int(error_fd, -errno); _exit(127); } if (options->env != NULL) { environ = options->env; } execvp(options->file, options->args); uv__write_int(error_fd, -errno); _exit(127); }
int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { uv_interface_address_t* address; int sockfd, size = 1; struct ifconf ifc; struct ifreq *ifr, *p, flg; *count = 0; if (0 > (sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP))) { return -errno; } if (ioctl(sockfd, SIOCGSIZIFCONF, &size) == -1) { SAVE_ERRNO(uv__close(sockfd)); return -errno; } ifc.ifc_req = (struct ifreq*)uv__malloc(size); ifc.ifc_len = size; if (ioctl(sockfd, SIOCGIFCONF, &ifc) == -1) { SAVE_ERRNO(uv__close(sockfd)); return -errno; } #define ADDR_SIZE(p) MAX((p).sa_len, sizeof(p)) /* Count all up and running ipv4/ipv6 addresses */ ifr = ifc.ifc_req; while ((char*)ifr < (char*)ifc.ifc_req + ifc.ifc_len) { p = ifr; ifr = (struct ifreq*) ((char*)ifr + sizeof(ifr->ifr_name) + ADDR_SIZE(ifr->ifr_addr)); if (!(p->ifr_addr.sa_family == AF_INET6 || p->ifr_addr.sa_family == AF_INET)) continue; memcpy(flg.ifr_name, p->ifr_name, sizeof(flg.ifr_name)); if (ioctl(sockfd, SIOCGIFFLAGS, &flg) == -1) { SAVE_ERRNO(uv__close(sockfd)); return -errno; } if (!(flg.ifr_flags & IFF_UP && flg.ifr_flags & IFF_RUNNING)) continue; (*count)++; } /* Alloc the return interface structs */ *addresses = (uv_interface_address_t*) uv__malloc(*count * sizeof(uv_interface_address_t)); if (!(*addresses)) { uv__close(sockfd); return -ENOMEM; } address = *addresses; ifr = ifc.ifc_req; while ((char*)ifr < (char*)ifc.ifc_req + ifc.ifc_len) { p = ifr; ifr = (struct ifreq*) ((char*)ifr + sizeof(ifr->ifr_name) + ADDR_SIZE(ifr->ifr_addr)); if (!(p->ifr_addr.sa_family == AF_INET6 || p->ifr_addr.sa_family == AF_INET)) continue; memcpy(flg.ifr_name, p->ifr_name, sizeof(flg.ifr_name)); if (ioctl(sockfd, SIOCGIFFLAGS, &flg) == -1) { uv__close(sockfd); return -ENOSYS; } if (!(flg.ifr_flags & IFF_UP && flg.ifr_flags & IFF_RUNNING)) continue; /* All conditions above must match count loop */ address->name = uv__strdup(p->ifr_name); if (p->ifr_addr.sa_family == AF_INET6) { address->address.address6 = *((struct sockaddr_in6*) &p->ifr_addr); } else { address->address.address4 = *((struct sockaddr_in*) &p->ifr_addr); } /* TODO: Retrieve netmask using SIOCGIFNETMASK ioctl */ address->is_internal = flg.ifr_flags & IFF_LOOPBACK ? 1 : 0; address++; } #undef ADDR_SIZE uv__close(sockfd); return 0; }
void uv__io_poll(uv_loop_t* loop, int timeout) { struct uv__epoll_event events[1024]; struct uv__epoll_event* pe; struct uv__epoll_event e; QUEUE* q; uv__io_t* w; uint64_t base; uint64_t diff; int nevents; int count; int nfds; int fd; int op; int i; if (loop->nfds == 0) { assert(QUEUE_EMPTY(&loop->watcher_queue)); return; } while (!QUEUE_EMPTY(&loop->watcher_queue)) { q = QUEUE_HEAD(&loop->watcher_queue); QUEUE_REMOVE(q); QUEUE_INIT(q); w = QUEUE_DATA(q, uv__io_t, watcher_queue); assert(w->pevents != 0); assert(w->fd >= 0); assert(w->fd < (int) loop->nwatchers); e.events = w->pevents; e.data = w->fd; if (w->events == 0) op = UV__EPOLL_CTL_ADD; else op = UV__EPOLL_CTL_MOD; /* XXX Future optimization: do EPOLL_CTL_MOD lazily if we stop watching * events, skip the syscall and squelch the events after epoll_wait(). */ if (uv__epoll_ctl(loop->backend_fd, op, w->fd, &e)) { if (errno != EEXIST) abort(); assert(op == UV__EPOLL_CTL_ADD); /* We've reactivated a file descriptor that's been watched before. */ if (uv__epoll_ctl(loop->backend_fd, UV__EPOLL_CTL_MOD, w->fd, &e)) abort(); } w->events = w->pevents; } assert(timeout >= -1); base = loop->time; count = 48; /* Benchmarks suggest this gives the best throughput. */ for (;;) { nfds = uv__epoll_wait(loop->backend_fd, events, ARRAY_SIZE(events), timeout); /* Update loop->time unconditionally. It's tempting to skip the update when * timeout == 0 (i.e. non-blocking poll) but there is no guarantee that the * operating system didn't reschedule our process while in the syscall. */ SAVE_ERRNO(uv__update_time(loop)); if (nfds == 0) { assert(timeout != -1); return; } if (nfds == -1) { if (errno != EINTR) abort(); if (timeout == -1) continue; if (timeout == 0) return; /* Interrupted by a signal. Update timeout and poll again. */ goto update_timeout; } nevents = 0; for (i = 0; i < nfds; i++) { pe = events + i; fd = pe->data; assert(fd >= 0); assert((unsigned) fd < loop->nwatchers); w = loop->watchers[fd]; if (w == NULL) { /* File descriptor that we've stopped watching, disarm it. * * Ignore all errors because we may be racing with another thread * when the file descriptor is closed. */ uv__epoll_ctl(loop->backend_fd, UV__EPOLL_CTL_DEL, fd, pe); continue; } w->cb(loop, w, pe->events); nevents++; } if (nevents != 0) { if (nfds == ARRAY_SIZE(events) && --count != 0) { /* Poll for more events but don't block this time. */ timeout = 0; continue; } return; } if (timeout == 0) return; if (timeout == -1) continue; update_timeout: assert(timeout > 0); diff = loop->time - base; if (diff >= (uint64_t) timeout) return; timeout -= diff; } }