int _gpgme_io_read ( int fd, void *buffer, size_t count ) { int nread; struct reader_context_s *c = find_reader (fd,1); DEBUG2 ("fd %d: about to read %d bytes\n", fd, (int)count ); if ( !c ) { DEBUG0 ( "no reader thread\n"); return -1; } if (c->eof_shortcut) { DEBUG1 ("fd %d: EOF (again)", fd ); return 0; } LOCK (c->mutex); if (c->readpos == c->writepos && !c->error) { /*no data avail*/ UNLOCK (c->mutex); DEBUG2 ("fd %d: waiting for data from thread %p", fd, c->thread_hd); WaitForSingleObject (c->have_data_ev, INFINITE); DEBUG2 ("fd %d: data from thread %p available", fd, c->thread_hd); LOCK (c->mutex); } if (c->readpos == c->writepos || c->error) { UNLOCK (c->mutex); c->eof_shortcut = 1; if (c->eof) { DEBUG1 ("fd %d: EOF", fd ); return 0; } if (!c->error) { DEBUG1 ("fd %d: EOF but eof flag not set", fd ); return 0; } DEBUG1 ("fd %d: read error", fd ); return -1; } nread = c->readpos < c->writepos? c->writepos - c->readpos : READBUF_SIZE - c->readpos; if (nread > count) nread = count; memcpy (buffer, c->buffer+c->readpos, nread); c->readpos = (c->readpos + nread) % READBUF_SIZE; if (c->readpos == c->writepos && !c->eof) { if ( !ResetEvent (c->have_data_ev) ) DEBUG1 ("ResetEvent failed: ec=%d", (int)GetLastError ()); } if (!SetEvent (c->have_space_ev)) DEBUG1 ("SetEvent failed: ec=%d", (int)GetLastError ()); UNLOCK (c->mutex); DEBUG2 ("fd %d: got %d bytes\n", fd, nread ); if (nread > 0) _gpgme_debug (2, "fd %d: got `%.*s'\n", fd, nread, buffer); return nread; }
/* * Select on the list of fds. * Returns: -1 = error * 0 = timeout or nothing to select * >0 = number of signaled fds */ int _gpgme_io_select ( struct io_select_fd_s *fds, size_t nfds, int nonblock ) { HANDLE waitbuf[MAXIMUM_WAIT_OBJECTS]; int waitidx[MAXIMUM_WAIT_OBJECTS]; int code, nwait; int i, any; int count; void *dbg_help; restart: DEBUG_BEGIN (dbg_help, 3, "select on [ "); any = 0; nwait = 0; count = 0; for ( i=0; i < nfds; i++ ) { if ( fds[i].fd == -1 ) continue; fds[i].signaled = 0; if ( fds[i].for_read || fds[i].for_write ) { if ( fds[i].frozen ) { DEBUG_ADD1 (dbg_help, "f%d ", fds[i].fd ); } else if ( fds[i].for_read ) { struct reader_context_s *c = find_reader (fds[i].fd,1); if (!c) { DEBUG1 ("oops: no reader thread for fd %d", fds[i].fd); } else { if ( nwait >= DIM (waitbuf) ) { DEBUG_END (dbg_help, "oops ]"); DEBUG0 ("Too many objects for WFMO!" ); return -1; } waitidx[nwait] = i; waitbuf[nwait++] = c->have_data_ev; } DEBUG_ADD1 (dbg_help, "r%d ", fds[i].fd ); any = 1; } else if ( fds[i].for_write ) { struct writer_context_s *c = find_writer (fds[i].fd,1); if (!c) { DEBUG1 ("oops: no writer thread for fd %d", fds[i].fd); } else { if ( nwait >= DIM (waitbuf) ) { DEBUG_END (dbg_help, "oops ]"); DEBUG0 ("Too many objects for WFMO!" ); return -1; } waitidx[nwait] = i; waitbuf[nwait++] = c->is_empty; } DEBUG_ADD1 (dbg_help, "w%d ", fds[i].fd ); any = 1; } } } DEBUG_END (dbg_help, "]"); if (!any) return 0; code = WaitForMultipleObjects ( nwait, waitbuf, 0, nonblock ? 0 : 1000); if ( code >= WAIT_OBJECT_0 && code < WAIT_OBJECT_0 + nwait ) { /* This WFMO is a really silly function: It does return either * the index of the signaled object or if 2 objects have been * signalled at the same time, the index of the object with the * lowest object is returned - so and how do we find out * how many objects have been signaled???. * The only solution I can imagine is to test each object starting * with the returned index individually - how dull. */ any = 0; for (i=code - WAIT_OBJECT_0; i < nwait; i++ ) { if (WaitForSingleObject (waitbuf[i], 0) == WAIT_OBJECT_0) { assert (waitidx[i] >=0 && waitidx[i] < nfds); fds[waitidx[i]].signaled = 1; any = 1; count++; } } if (!any) { DEBUG0 ("Oops: No signaled objects found after WFMO"); count = -1; } } else if ( code == WAIT_TIMEOUT ) { DEBUG0 ("WFMO timed out\n" ); } else if (code == WAIT_FAILED ) { int le = (int)GetLastError (); if ( le == ERROR_INVALID_HANDLE ) { int k, j = handle_to_fd (waitbuf[i]); DEBUG1 ("WFMO invalid handle %d removed\n", j); for (k=0 ; k < nfds; k++ ) { if ( fds[k].fd == j ) { fds[k].for_read = fds[k].for_write = 0; goto restart; } } DEBUG0 (" oops, or not???\n"); } DEBUG1 ("WFMO failed: %d\n", le ); count = -1; } else { DEBUG1 ("WFMO returned %d\n", code ); count = -1; } if ( count ) { DEBUG_BEGIN (dbg_help, 3, " signaled [ "); for ( i=0; i < nfds; i++ ) { if ( fds[i].fd == -1 ) continue; if ( (fds[i].for_read || fds[i].for_write) && fds[i].signaled ) { DEBUG_ADD2 (dbg_help, "%c%d ", fds[i].for_read? 'r':'w',fds[i].fd ); } } DEBUG_END (dbg_help, "]"); } return count; }
int _gpgme_io_pipe (int filedes[2], int inherit_idx) { HANDLE rh; HANDLE wh; SECURITY_ATTRIBUTES sec_attr; TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_pipe", filedes, "inherit_idx=%i (GPGME uses it for %s)", inherit_idx, inherit_idx ? "reading" : "writing"); memset (&sec_attr, 0, sizeof (sec_attr)); sec_attr.nLength = sizeof (sec_attr); sec_attr.bInheritHandle = FALSE; if (!CreatePipe (&rh, &wh, &sec_attr, PIPEBUF_SIZE)) { TRACE_LOG1 ("CreatePipe failed: ec=%d", (int) GetLastError ()); /* FIXME: Should translate the error code. */ errno = EIO; return TRACE_SYSRES (-1); } /* Make one end inheritable. */ if (inherit_idx == 0) { struct writer_context_s *ctx; HANDLE hd; if (!DuplicateHandle (GetCurrentProcess(), rh, GetCurrentProcess(), &hd, 0, TRUE, DUPLICATE_SAME_ACCESS)) { TRACE_LOG1 ("DuplicateHandle failed: ec=%d", (int) GetLastError ()); CloseHandle (rh); CloseHandle (wh); /* FIXME: Should translate the error code. */ errno = EIO; return TRACE_SYSRES (-1); } CloseHandle (rh); rh = hd; ctx = find_writer (handle_to_fd (wh), 0); assert (ctx == NULL); ctx = find_writer (handle_to_fd (wh), 1); if (!ctx) { CloseHandle (rh); CloseHandle (wh); /* FIXME: Should translate the error code. */ errno = EIO; return TRACE_SYSRES (-1); } } else if (inherit_idx == 1) { struct reader_context_s *ctx; HANDLE hd; if (!DuplicateHandle( GetCurrentProcess(), wh, GetCurrentProcess(), &hd, 0, TRUE, DUPLICATE_SAME_ACCESS)) { TRACE_LOG1 ("DuplicateHandle failed: ec=%d", (int) GetLastError ()); CloseHandle (rh); CloseHandle (wh); /* FIXME: Should translate the error code. */ errno = EIO; return TRACE_SYSRES (-1); } CloseHandle (wh); wh = hd; ctx = find_reader (handle_to_fd (rh), 0); assert (ctx == NULL); ctx = find_reader (handle_to_fd (rh), 1); if (!ctx) { CloseHandle (rh); CloseHandle (wh); /* FIXME: Should translate the error code. */ errno = EIO; return TRACE_SYSRES (-1); } } filedes[0] = handle_to_fd (rh); filedes[1] = handle_to_fd (wh); return TRACE_SUC2 ("read=%p, write=%p", rh, wh); }
int _gpgme_io_read (int fd, void *buffer, size_t count) { int nread; struct reader_context_s *ctx; TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_read", fd, "buffer=%p, count=%u", buffer, count); ctx = find_reader (fd, 1); if (!ctx) { errno = EBADF; return TRACE_SYSRES (-1); } if (ctx->eof_shortcut) return TRACE_SYSRES (0); LOCK (ctx->mutex); if (ctx->readpos == ctx->writepos && !ctx->error) { /* No data available. */ UNLOCK (ctx->mutex); TRACE_LOG1 ("waiting for data from thread %p", ctx->thread_hd); WaitForSingleObject (ctx->have_data_ev, INFINITE); TRACE_LOG1 ("data from thread %p available", ctx->thread_hd); LOCK (ctx->mutex); } if (ctx->readpos == ctx->writepos || ctx->error) { UNLOCK (ctx->mutex); ctx->eof_shortcut = 1; if (ctx->eof) return TRACE_SYSRES (0); if (!ctx->error) { TRACE_LOG ("EOF but ctx->eof flag not set"); return 0; } errno = ctx->error_code; return TRACE_SYSRES (-1); } nread = ctx->readpos < ctx->writepos ? ctx->writepos - ctx->readpos : READBUF_SIZE - ctx->readpos; if (nread > count) nread = count; memcpy (buffer, ctx->buffer + ctx->readpos, nread); ctx->readpos = (ctx->readpos + nread) % READBUF_SIZE; if (ctx->readpos == ctx->writepos && !ctx->eof) { if (!ResetEvent (ctx->have_data_ev)) { TRACE_LOG1 ("ResetEvent failed: ec=%d", (int) GetLastError ()); UNLOCK (ctx->mutex); /* FIXME: Should translate the error code. */ errno = EIO; return TRACE_SYSRES (-1); } } if (!SetEvent (ctx->have_space_ev)) { TRACE_LOG2 ("SetEvent (0x%x) failed: ec=%d", ctx->have_space_ev, (int) GetLastError ()); UNLOCK (ctx->mutex); /* FIXME: Should translate the error code. */ errno = EIO; return TRACE_SYSRES (-1); } UNLOCK (ctx->mutex); TRACE_LOGBUF (buffer, nread); return TRACE_SYSRES (nread); }
int _gpgme_io_dup (int fd) { HANDLE handle = fd_to_handle (fd); HANDLE new_handle = fd_to_handle (fd); int i; struct reader_context_s *rd_ctx; struct writer_context_s *wt_ctx; TRACE_BEG (DEBUG_SYSIO, "_gpgme_io_dup", fd); if (!DuplicateHandle (GetCurrentProcess(), handle, GetCurrentProcess(), &new_handle, 0, FALSE, DUPLICATE_SAME_ACCESS)) { TRACE_LOG1 ("DuplicateHandle failed: ec=%d\n", (int) GetLastError ()); /* FIXME: Translate error code. */ errno = EIO; return TRACE_SYSRES (-1); } rd_ctx = find_reader (fd, 0); if (rd_ctx) { /* No need for locking, as the only races are against the reader thread itself, which doesn't touch refcount. */ rd_ctx->refcount++; LOCK (reader_table_lock); for (i = 0; i < reader_table_size; i++) if (!reader_table[i].used) break; /* FIXME. */ assert (i != reader_table_size); reader_table[i].fd = handle_to_fd (new_handle); reader_table[i].context = rd_ctx; reader_table[i].used = 1; UNLOCK (reader_table_lock); } wt_ctx = find_writer (fd, 0); if (wt_ctx) { /* No need for locking, as the only races are against the writer thread itself, which doesn't touch refcount. */ wt_ctx->refcount++; LOCK (writer_table_lock); for (i = 0; i < writer_table_size; i++) if (!writer_table[i].used) break; /* FIXME. */ assert (i != writer_table_size); writer_table[i].fd = handle_to_fd (new_handle); writer_table[i].context = wt_ctx; writer_table[i].used = 1; UNLOCK (writer_table_lock); } return TRACE_SYSRES (handle_to_fd (new_handle)); }
/* Select on the list of fds. Returns: -1 = error, 0 = timeout or nothing to select, > 0 = number of signaled fds. */ int _gpgme_io_select (struct io_select_fd_s *fds, size_t nfds, int nonblock) { HANDLE waitbuf[MAXIMUM_WAIT_OBJECTS]; int waitidx[MAXIMUM_WAIT_OBJECTS]; int code; int nwait; int i; int any; int count; void *dbg_help; TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_select", fds, "nfds=%u, nonblock=%u", nfds, nonblock); restart: TRACE_SEQ (dbg_help, "select on [ "); any = 0; nwait = 0; count = 0; for (i=0; i < nfds; i++) { if (fds[i].fd == -1) continue; fds[i].signaled = 0; if (fds[i].for_read || fds[i].for_write) { if (fds[i].for_read) { struct reader_context_s *ctx = find_reader (fds[i].fd,0); if (!ctx) TRACE_LOG1 ("error: no reader for FD 0x%x (ignored)", fds[i].fd); else { if (nwait >= DIM (waitbuf)) { TRACE_END (dbg_help, "oops ]"); TRACE_LOG ("Too many objects for WFMO!"); /* FIXME: Should translate the error code. */ errno = EIO; return TRACE_SYSRES (-1); } waitidx[nwait] = i; waitbuf[nwait++] = ctx->have_data_ev; } TRACE_ADD1 (dbg_help, "r0x%x ", fds[i].fd); any = 1; } else if (fds[i].for_write) { struct writer_context_s *ctx = find_writer (fds[i].fd,0); if (!ctx) TRACE_LOG1 ("error: no writer for FD 0x%x (ignored)", fds[i].fd); else { if (nwait >= DIM (waitbuf)) { TRACE_END (dbg_help, "oops ]"); TRACE_LOG ("Too many objects for WFMO!"); /* FIXME: Should translate the error code. */ errno = EIO; return TRACE_SYSRES (-1); } waitidx[nwait] = i; waitbuf[nwait++] = ctx->is_empty; } TRACE_ADD1 (dbg_help, "w0x%x ", fds[i].fd); any = 1; } } } TRACE_END (dbg_help, "]"); if (!any) return TRACE_SYSRES (0); code = WaitForMultipleObjects (nwait, waitbuf, 0, nonblock ? 0 : 1000); if (code >= WAIT_OBJECT_0 && code < WAIT_OBJECT_0 + nwait) { /* This WFMO is a really silly function: It does return either the index of the signaled object or if 2 objects have been signalled at the same time, the index of the object with the lowest object is returned - so and how do we find out how many objects have been signaled???. The only solution I can imagine is to test each object starting with the returned index individually - how dull. */ any = 0; for (i = code - WAIT_OBJECT_0; i < nwait; i++) { if (WaitForSingleObject (waitbuf[i], 0) == WAIT_OBJECT_0) { assert (waitidx[i] >=0 && waitidx[i] < nfds); fds[waitidx[i]].signaled = 1; any = 1; count++; } } if (!any) { TRACE_LOG ("no signaled objects found after WFMO"); count = -1; } } else if (code == WAIT_TIMEOUT) TRACE_LOG ("WFMO timed out"); else if (code == WAIT_FAILED) { int le = (int) GetLastError (); if (le == ERROR_INVALID_HANDLE) { int k; int j = handle_to_fd (waitbuf[i]); TRACE_LOG1 ("WFMO invalid handle %d removed", j); for (k = 0 ; k < nfds; k++) { if (fds[k].fd == j) { fds[k].for_read = fds[k].for_write = 0; goto restart; } } TRACE_LOG (" oops, or not???"); } TRACE_LOG1 ("WFMO failed: %d", le); count = -1; } else { TRACE_LOG1 ("WFMO returned %d", code); count = -1; } if (count > 0) { TRACE_SEQ (dbg_help, "select OK [ "); for (i = 0; i < nfds; i++) { if (fds[i].fd == -1) continue; if ((fds[i].for_read || fds[i].for_write) && fds[i].signaled) TRACE_ADD2 (dbg_help, "%c0x%x ", fds[i].for_read ? 'r' : 'w', fds[i].fd); } TRACE_END (dbg_help, "]"); } if (count < 0) { /* FIXME: Should determine a proper error code. */ errno = EIO; } return TRACE_SYSRES (count); }
int __nisdb_rlock(__nisdb_rwlock_t *rw) { int ret; pthread_t myself = pthread_self(); __nisdb_rl_t *rr; if (rw == 0) { #ifdef NISDB_MT_DEBUG /* This shouldn't happen */ abort(); #endif /* NISDB_MT_DEBUG */ return (EFAULT); } if (rw->destroyed != 0) return (ESHUTDOWN); if (rw->force_write) return (__nisdb_wlock(rw)); if ((ret = mutex_lock(&rw->mutex)) != 0) return (ret); if (rw->destroyed != 0) { (void) mutex_unlock(&rw->mutex); return (ESHUTDOWN); } rr = find_reader(myself, rw); /* Wait for writer to complete; writer == myself also OK */ while (rw->writer_count > 0 && rw->writer.id != myself) { if (rr != 0) { rr->wait = 1; rw->reader_blocked++; } if ((ret = cond_wait(&rw->cv, &rw->mutex)) != 0) { if (rr != 0) { rr->wait = 0; if (rw->reader_blocked > 0) rw->reader_blocked--; #ifdef NISDB_MT_DEBUG else abort(); #endif /* NISDB_MT_DEBUG */ } (void) mutex_unlock(&rw->mutex); return (ret); } if (rr != 0) { rr->wait = 0; if (rw->reader_blocked > 0) rw->reader_blocked--; #ifdef NISDB_MT_DEBUG else abort(); #endif /* NISDB_MT_DEBUG */ } } rr = increment_reader(myself, rw); ret = mutex_unlock(&rw->mutex); return ((rr == 0) ? ENOMEM : ret); }
int __nisdb_wlock_trylock(__nisdb_rwlock_t *rw, int trylock) { int ret; pthread_t myself = pthread_self(); int all_readers_blocked = 0; __nisdb_rl_t *rr = 0; if (rw == 0) { #ifdef NISDB_MT_DEBUG /* This shouldn't happen */ abort(); #endif /* NISDB_MT_DEBUG */ return (EFAULT); } if (rw->destroyed != 0) return (ESHUTDOWN); if ((ret = mutex_lock(&rw->mutex)) != 0) return (ret); if (rw->destroyed != 0) { (void) mutex_unlock(&rw->mutex); return (ESHUTDOWN); } /* Simplest (and probably most common) case: no readers or writers */ if (rw->reader_count == 0 && rw->writer_count == 0) { rw->writer_count = 1; rw->writer.id = myself; rw->writer.count = 1; return (mutex_unlock(&rw->mutex)); } /* * Need to know if we're holding a read lock already, and if * all other readers are blocked waiting for the mutex. */ if (rw->reader_count > 0) { if ((rr = find_reader(myself, rw)) != 0) { if (rr->count) /* * We're already holding a read lock, so * if the number of readers equals the number * of blocked readers plus one, all other * readers are blocked. */ if (rw->reader_count == (rw->reader_blocked + 1)) all_readers_blocked = 1; else /* * We're not holding a read lock, so the * number of readers should equal the number * of blocked readers if all readers are * blocked. */ if (rw->reader_count == rw->reader_blocked) all_readers_blocked = 1; } } /* Wait for reader(s) or writer to finish */ while (1) { /* * We can stop looping if one of the following holds: * - No readers, no writers * - No writers (or writer is myself), and one of: * - No readers * - One reader, and it's us * - N readers, but all blocked on the mutex */ if ( (rw->writer_count == 0 && rw->reader_count == 0) || ((rw->writer_count == 0 || rw->writer.id == myself) && (rw->reader_count == 0) || (rw->reader_count == 1 && rw->reader.id == myself))) { break; } /* * Provided that all readers are blocked on the mutex * we break a potential dead-lock by acquiring the * write lock. */ if (all_readers_blocked) { if (rw->writer_count == 0 || rw->writer.id == myself) { break; } } /* * If 'trylock' is set, tell the caller that we'd have to * block to obtain the lock. */ if (trylock) { (void) mutex_unlock(&rw->mutex); return (EBUSY); } /* If we're also a reader, indicate that we're blocking */ if (rr != 0) { rr->wait = 1; rw->reader_blocked++; } if ((ret = cond_wait(&rw->cv, &rw->mutex)) != 0) { if (rr != 0) { rr->wait = 0; if (rw->reader_blocked > 0) rw->reader_blocked--; #ifdef NISDB_MT_DEBUG else abort(); #endif /* NISDB_MT_DEBUG */ } (void) mutex_unlock(&rw->mutex); return (ret); } if (rr != 0) { rr->wait = 0; if (rw->reader_blocked > 0) rw->reader_blocked--; #ifdef NISDB_MT_DEBUG else abort(); #endif /* NISDB_MT_DEBUG */ } } /* OK to grab the write lock */ rw->writer.id = myself; /* Increment lock depth */ rw->writer.count++; /* Set number of writers (doesn't increase with lock depth) */ if (rw->writer_count == 0) rw->writer_count = 1; return (mutex_unlock(&rw->mutex)); }