static int ghbn_init(rktio_t *rktio) { rktio->ghbn_lock = CreateSemaphore(NULL, 1, 1, NULL); if (!rktio->ghbn_lock) { get_windows_error(); return 0; } rktio->ghbn_start = CreateSemaphore(NULL, 0, 1, NULL); if (!rktio->ghbn_start) { get_windows_error(); return 0; } rktio->ghbn_th = (HANDLE)_beginthreadex(NULL, 5000, win_getaddrinfo_in_thread, rktio, 0, NULL); if (rktio->ghbn_th == INVALID_HANDLE_VALUE) { get_posix_error(); return 0; } return 1; }
rktio_status_t *rktio_process_status(rktio_t *rktio, rktio_process_t *sp) { int going = 0, status = 0; rktio_status_t *result; #if defined(RKTIO_SYSTEM_UNIX) # if defined(CENTRALIZED_SIGCHILD) if (sp->done) { status = sp->status; } else { if (!centralized_get_child_status(sp->pid, sp->in_group, 1, &status)) { going = 1; } else { sp->done = 1; sp->status = status; centralized_ended_child(); } } # else System_Child *sc = (System_Child *)sp->handle; check_child_done(rktio, sp->pid); if (sc->done) { status = sc->status; } else going = 1; # endif #else # ifdef RKTIO_SYSTEM_WINDOWS DWORD w; if (sp->handle) { if (GetExitCodeProcess((HANDLE)sp->handle, &w)) { collect_process_time(rktio, w, sp); if (w == STILL_ACTIVE) going = 1; else status = w; } else { get_windows_error(); return NULL; } } else status = -1; # endif #endif result = malloc(sizeof(rktio_status_t)); result->running = going; result->result = (going ? 0 : status); return result; }
int rktio_poll_process_done(rktio_t *rktio, rktio_process_t *sp) { #if defined(RKTIO_SYSTEM_UNIX) # if defined(CENTRALIZED_SIGCHILD) { int status; if (!sp->done) { if (centralized_get_child_status(sp->pid, sp->in_group, 1, &status)) { sp->done = 1; sp->status = status; centralized_ended_child(); return 1; } return 0; } else return RKTIO_PROCESS_DONE; } # else { System_Child *sc; sc = (System_Child *)sp->handle; /* Check specific pid, in case the child has its own group (either given by us or given to itself): */ check_child_done(rktio, sp->pid); return sc->done; } # endif #endif #ifdef RKTIO_SYSTEM_WINDOWS { HANDLE sci = (HANDLE)sp->handle; DWORD w; if (sci) { if (GetExitCodeProcess(sci, &w)) { collect_process_time(rktio, w, sp); return (w != STILL_ACTIVE); } else return RKTIO_PROCESS_DONE; } else return RKTIO_PROCESS_DONE; get_windows_error(); return RKTIO_PROCESS_ERROR; } #endif }
static rktio_ok_t do_close(rktio_t *rktio, rktio_fd_t *rfd, int set_error) { int ok; #ifdef RKTIO_SYSTEM_UNIX int cr; # ifdef RKTIO_USE_FCNTL_AND_FORK_FOR_FILE_LOCKS if (!(rfd->modes & RKTIO_OPEN_SOCKET)) rktio_release_lockf(rktio, rfd->fd); # endif cr = rktio_reliably_close_err(rfd->fd); if (cr && set_error) { get_posix_error(); ok = 0; } else ok = 1; #endif #ifdef RKTIO_SYSTEM_WINDOWS if (rfd->modes & RKTIO_OPEN_SOCKET) return rktio_socket_close(rktio, rfd, set_error); deinit_fd(rktio, rfd, 1); ok = 1; if (!rfd->th && !rfd->oth) { if (!CloseHandle(rfd->fd)) { ok = 0; get_windows_error(); } } #endif if (ok) free(rfd); return ok; }
rktio_fd_t *rktio_dup(rktio_t *rktio, rktio_fd_t *rfd) { #ifdef RKTIO_SYSTEM_UNIX intptr_t nfd; do { nfd = dup(rfd->fd); } while (nfd == -1 && errno == EINTR); if (nfd == -1) { get_posix_error(); return NULL; } else { /* Set the `RKTIO_OPEN_INIT` flag, because dup()ing a file descriptor does not keep all of its properties on some platforms (e.g., the non-blocking property on sockets on Linux). */ return rktio_system_fd(rktio, nfd, rfd->modes | RKTIO_OPEN_INIT); } #endif #ifdef RKTIO_SYSTEM_WINDOWS if (rfd->modes & RKTIO_OPEN_SOCKET) { return rktio_socket_dup(rktio, rfd); } else { HANDLE newhandle; BOOL rc; rc = DuplicateHandle(GetCurrentProcess(), rfd->fd, GetCurrentProcess(), &newhandle, 0, FALSE, DUPLICATE_SAME_ACCESS); if (rc == FALSE) { get_windows_error(); return NULL; } else { return rktio_system_fd(rktio, (intptr_t)newhandle, rfd->modes); } } #endif }
static rktio_addrinfo_lookup_t *start_lookup(rktio_t *rktio, rktio_addrinfo_lookup_t *lookup) { lookup->mode = GHBN_WAIT; if (!rktio->ghbn_started) { rktio->ghbn_run = 1; if (!ghbn_init(rktio)) return NULL; rktio->ghbn_started = 1; } # ifdef RKTIO_SYSTEM_WINDOWS { lookup->done_sema = CreateSemaphore(NULL, 0, 1, NULL); if (!lookup->done_sema) { get_windows_error(); free_lookup(lookup); return NULL; } } # else if (pipe(lookup->done_fd)) { get_posix_error(); free_lookup(lookup); return NULL; } else { fcntl(lookup->done_fd[0], F_SETFL, RKTIO_NONBLOCKING); } # endif ghbn_lock(rktio); lookup->next = rktio->ghbn_requests; rktio->ghbn_requests = lookup; ghbn_signal(rktio); ghbn_unlock(rktio); return lookup; }
int rktio_winsock_init(rktio_t *rktio) { if (!winsock_sema) { winsock_sema = CreateSemaphore(NULL, 1, 1, NULL); } WaitForSingleObject(winsock_sema, INFINITE); if (!winsock_started) { WSADATA data; if (!WSAStartup(MAKEWORD(1, 1), &data)) { winsock_started = 1; } else { get_windows_error(); ReleaseSemaphore(winsock_sema, 1, NULL); return 0; } } else winsock_started++; ReleaseSemaphore(winsock_sema, 1, NULL); return 1; }
static int do_subprocess_kill(rktio_t *rktio, rktio_process_t *sp, int as_kill) { #if defined(RKTIO_SYSTEM_UNIX) # if defined(CENTRALIZED_SIGCHILD) { int status; if (sp->done) return 1; centralized_wait_suspend(); /* Don't allow group checking, because we don't want to wait on a group if we haven't already: */ if (centralized_get_child_status(sp->pid, 0, 0, &status)) { sp->status = status; sp->done = 1; centralized_wait_resume(); centralized_ended_child(); return 1; } } # else { System_Child *sc = (System_Child *)sp->handle; /* Don't pass sp->pid, because we don't want to wait on a group if we haven't already: */ check_child_done(rktio, 0); if (sc->done) return 1; } # define centralized_wait_resume() /* empty */ # endif while (1) { if (sp->is_group) { if (!killpg(sp->pid, as_kill ? SIGKILL : SIGINT)) { centralized_wait_resume(); return 1; } } else { if (!kill(sp->pid, as_kill ? SIGKILL : SIGINT)) { centralized_wait_resume(); return 1; } } if (errno != EINTR) break; /* Otherwise we were interrupted. Try `kill' again. */ } get_posix_error(); centralized_wait_resume(); return 0; #endif #if defined(RKTIO_SYSTEM_WINDOWS) if (as_kill || sp->is_group) { DWORD w; if (!sp->handle) return 1; if (!as_kill) { /* must be for a group; we don't care whether the original process is still running */ if (GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, sp->pid)) return 1; } else if (GetExitCodeProcess((HANDLE)sp->handle, &w)) { collect_process_time(rktio, w, sp); if (w != STILL_ACTIVE) return 1; if (TerminateProcess((HANDLE)sp->handle, 1)) return 1; } get_windows_error(); return 0; } else return 1; #endif }
intptr_t rktio_read_converted(rktio_t *rktio, rktio_fd_t *rfd, char *buffer, intptr_t len, char *is_converted) { #ifdef RKTIO_SYSTEM_UNIX intptr_t bc; if (rfd->modes & RKTIO_OPEN_SOCKET) return rktio_socket_read(rktio, rfd, buffer, len); # ifdef SOME_FDS_ARE_NOT_SELECTABLE if (rfd->bufcount && len) { buffer[0] = rfd->buffer[0]; rfd->bufcount = 0; return 1; } # endif if (rktio_fd_is_regular_file(rktio, rfd)) { /* Reading regular file never blocks */ do { bc = read(rfd->fd, buffer, len); } while ((bc == -1) && (errno == EINTR)); if (bc == -1) { get_posix_error(); return RKTIO_READ_ERROR; } else if (bc == 0) return RKTIO_READ_EOF; else return bc; } else { /* We use a non-blocking read here, even though we've waited for input above, because an external process might have gobbled the characters that we expected to get. */ int old_flags; old_flags = fcntl(rfd->fd, F_GETFL, 0); if (!(old_flags & RKTIO_NONBLOCKING)) fcntl(rfd->fd, F_SETFL, old_flags | RKTIO_NONBLOCKING); do { bc = read(rfd->fd, buffer, len); } while ((bc == -1) && errno == EINTR); if ((bc == -1) && (errno != EAGAIN)) get_posix_error(); if (!(old_flags & RKTIO_NONBLOCKING)) fcntl(rfd->fd, F_SETFL, old_flags); if (bc == -1) { if (errno == EAGAIN) return 0; /* no bytes from a non-blocking read */ else return RKTIO_READ_ERROR; } else if (bc == 0) return RKTIO_READ_EOF; else return bc; } #endif #ifdef RKTIO_SYSTEM_WINDOWS if (rfd->modes & RKTIO_OPEN_SOCKET) return rktio_socket_read(rktio, rfd, buffer, len); init_read_fd(rktio, rfd); if (!rfd->th) { /* We can read directly. This must be a regular file, where reading never blocks. */ DWORD rgot, offset = 0; if (rfd->has_pending_byte) { if (!len) return 0; buffer[0] = rfd->pending_byte; if (len == 1) { if (rfd->pending_byte == '\r') { /* We have to read one more byte and then decode, shifting the new byte into pending position if it's not '\n' */ } else { if (is_converted) is_converted[0] = 0; rfd->has_pending_byte = 0; return 1; } } else { /* read after first byte installed into the buffer */ offset = 1; } } if (!ReadFile((HANDLE)rfd->fd, buffer + offset, len - offset, &rgot, NULL)) { get_windows_error(); return RKTIO_READ_ERROR; } rgot += offset; if (rfd->has_pending_byte) { /* We had a buffer of size 1 and a pending '\r'... */ return adjust_input_text_for_pending_cr(rfd, buffer, is_converted, rgot); } else if (!rgot) return RKTIO_READ_EOF; else if (rfd->modes & RKTIO_OPEN_TEXT) return adjust_input_text(rfd, buffer, is_converted, rgot, offset); else return rgot; } else { if (!rktio_poll_read_ready(rktio, rfd)) return 0; /* If we get this far, there should be data available. Extract data made available by the reader thread. */ WaitForSingleObject(rfd->th->lock_sema, INFINITE); if (rfd->th->eof) { if (rfd->th->eof != INVALID_HANDLE_VALUE) { ReleaseSemaphore(rfd->th->eof, 1, NULL); rfd->th->eof = NULL; } ReleaseSemaphore(rfd->th->lock_sema, 1, NULL); return RKTIO_READ_EOF; } else if (rfd->th->err) { ReleaseSemaphore(rfd->th->lock_sema, 1, NULL); set_windows_error(rfd->th->err); return RKTIO_READ_ERROR; } else { intptr_t bc = rfd->th->avail; if (bc > len) bc = len; rfd->th->avail -= bc; memcpy(buffer, rfd->buffer + rfd->th->offset, bc); rfd->th->offset += bc; ReleaseSemaphore(rfd->th->lock_sema, 1, NULL); return bc; } } #endif }
mapped_file::mapped_file(const string & fname, unsigned int io_open_mode, unsigned int create_size) : file_handle(0), map_handle(0), map_pointer(0) { #ifdef WIN32 string full_path = io::file::get_full_path(fname); // open file handle unsigned int win_open_mode = GENERIC_READ; if (io_open_mode & io::FILE_OPEN_WRITE) win_open_mode |= GENERIC_WRITE; if (file::exists(full_path)) { file_handle = CreateFileW(full_path.w_string(), win_open_mode, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); if (file_handle != INVALID_HANDLE_VALUE) create_size = GetFileSize(file_handle, 0); } else { if (create_size == 0) throw internal_exception(__FILE__, __LINE__, L"Must specify size for creating memory-mapped files."); file_handle = CreateFileW(full_path.w_string(), win_open_mode, 0, 0, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0); if (file_handle != INVALID_HANDLE_VALUE) { unsigned char buf = 0; unsigned int written; SetFilePointer(file_handle, create_size-1, 0, FILE_BEGIN); WriteFile(file_handle, &buf, 1, (LPDWORD) &written, 0); SetFilePointer(file_handle, 0, 0, FILE_BEGIN); } } if (file_handle == INVALID_HANDLE_VALUE) throw io_exception(L"Unable to open %ls: %ls", full_path.w_string(), get_windows_error().w_string()); // create mapping string map_name = string::format(L"periapsis_mapped_file_%d", NUM_MAPPED_FILES++); if (io_open_mode & io::FILE_OPEN_WRITE) win_open_mode = PAGE_READWRITE; else win_open_mode = PAGE_READONLY; map_handle = CreateFileMappingW(file_handle, 0, win_open_mode, 0, create_size, map_name.w_string()); if (!map_handle) throw io_exception(L"Unable to create memory map for %ls: %ls", full_path.w_string(), get_windows_error().w_string()); // map file if (io_open_mode & io::FILE_OPEN_WRITE) win_open_mode = FILE_MAP_ALL_ACCESS; else win_open_mode = FILE_MAP_READ; map_pointer = MapViewOfFile(map_handle, win_open_mode, 0, 0, 0); if (!map_pointer) throw io_exception(L"Unable to create memory map for %ls: %ls", full_path.w_string(), get_windows_error().w_string()); map_size = create_size; #else #error Implement memory-mapped files! #endif } // mapped_file::mapped_file()