// Must be called with the mutex held static void initiate_write(struct win_handle *h) { struct write_buf *wbuf = h->write_head; if (h->write_pending || !wbuf) { return; } h->write_head = wbuf->next; if (!h->write_head) { h->write_tail = NULL; } h->write_pending = calloc(1, sizeof(*h->write_pending)); h->write_pending->h = h; h->write_pending->wbuf = wbuf; if (!WriteFileEx(h->h, wbuf->cursor, wbuf->len, &h->write_pending->olap, write_completed)) { stream_debug("WriteFileEx: failed %s\n", win32_strerror(GetLastError())); free(h->write_pending); h->write_pending = NULL; } else { stream_debug("WriteFileEx: queued %d bytes for later\n", wbuf->len); } }
static int win_read_blocking(struct win_handle *h, char *buf, int size) { int total_read = 0; DWORD bytes, err; move_from_read_buffer(h, &total_read, &buf, &size); if (size == 0) { return total_read; } stream_debug("blocking read of %d bytes\n", (int)size); if (ReadFile(h->h, buf, size, &bytes, NULL)) { total_read += bytes; stream_debug("blocking read provided %d bytes, total=%d\n", (int)bytes, total_read); return total_read; } err = GetLastError(); stream_debug("blocking read failed: %s\n", win32_strerror(err)); if (total_read) { stream_debug("but already got %d bytes from buffer\n", total_read); return total_read; } errno = map_win32_err(err); return -1; }
int audio_debug(struct re_printf *pf, const struct audio *a) { const struct autx *tx; const struct aurx *rx; int err; if (!a) return 0; tx = &a->tx; rx = &a->rx; err = re_hprintf(pf, "\n--- Audio stream ---\n"); err |= re_hprintf(pf, " tx: %H %H ptime=%ums\n", aucodec_print, tx->ac, aubuf_debug, tx->ab, tx->ptime); err |= re_hprintf(pf, " rx: %H %H ptime=%ums pt=%d\n", aucodec_print, rx->ac, aubuf_debug, rx->ab, rx->ptime, rx->pt); err |= stream_debug(pf, a->strm); return err; }
static void move_from_read_buffer(struct win_handle *h, int *total_read_ptr, char **target_buf_ptr, int *size_ptr) { int nread = MIN(*size_ptr, h->read_avail); size_t wasted; if (!nread) { return; } memcpy(*target_buf_ptr, h->read_cursor, nread); *total_read_ptr += nread; *target_buf_ptr += nread; *size_ptr -= nread; h->read_cursor += nread; h->read_avail -= nread; stream_debug("moved %d bytes from buffer\n", nread); // Pack the buffer to free up space at the rear for reads wasted = h->read_cursor - h->read_buf; if (wasted) { memmove(h->read_buf, h->read_cursor, h->read_avail); h->read_cursor = h->read_buf; } }
static int win_write(w_stm_t stm, const void *buf, int size) { struct win_handle *h = stm->handle; struct write_buf *wbuf; EnterCriticalSection(&h->mtx); if (h->file_type != FILE_TYPE_PIPE && h->blocking && !h->write_head) { DWORD bytes; stream_debug("blocking write of %d\n", size); if (WriteFile(h->h, buf, size, &bytes, NULL)) { LeaveCriticalSection(&h->mtx); return bytes; } h->errcode = GetLastError(); h->error_pending = true; errno = map_win32_err(h->errcode); SetEvent(h->waitable); stream_debug("write failed: %s\n", win32_strerror(h->errcode)); LeaveCriticalSection(&h->mtx); return -1; } wbuf = malloc(sizeof(*wbuf) + size - 1); if (!wbuf) { return -1; } wbuf->next = NULL; wbuf->cursor = wbuf->data; wbuf->len = size; memcpy(wbuf->data, buf, size); if (h->write_tail) { h->write_tail->next = wbuf; } else { h->write_head = wbuf; } h->write_tail = wbuf; if (!h->write_pending) { initiate_write(h); } LeaveCriticalSection(&h->mtx); return size; }
static void CALLBACK write_completed(DWORD err, DWORD bytes, LPOVERLAPPED olap) { // Reverse engineer our handle from the olap pointer struct overlapped_op *op = (void*)olap; struct win_handle *h = op->h; struct write_buf *wbuf = op->wbuf; stream_debug("WriteFileEx: completion callback invoked: bytes=%d %s\n", (int)bytes, win32_strerror(err)); EnterCriticalSection(&h->mtx); if (h->write_pending == op) { h->write_pending = NULL; } if (err == 0) { wbuf->cursor += bytes; wbuf->len -= bytes; if (wbuf->len == 0) { // Consumed this buffer free(wbuf); } else { w_log(W_LOG_FATAL, "WriteFileEx: short write: %d written, %d remain\n", bytes, wbuf->len); } } else { stream_debug("WriteFilex: completion: failed: %s\n", win32_strerror(err)); h->errcode = err; h->error_pending = true; SetEvent(h->waitable); } // Send whatever else we have waiting to go initiate_write(h); LeaveCriticalSection(&h->mtx); // Free the prior struct after possibly initiating another write // to minimize the change of the same address being reused and // confusing the completion status free(op); }
static int win_read_non_blocking(struct win_handle *h, char *buf, int size) { int total_read = 0; char *target; DWORD target_space; DWORD bytes; stream_debug("non_blocking read for %d bytes\n", size); move_from_read_buffer(h, &total_read, &buf, &size); target = h->read_cursor + h->read_avail; target_space = (DWORD)((h->read_buf + sizeof(h->read_buf)) - target); stream_debug("initiate read for %d\n", target_space); // Create a unique olap for each request h->read_pending = calloc(1, sizeof(*h->read_pending)); if (h->read_avail == 0) { ResetEvent(h->waitable); } h->read_pending->olap.hEvent = h->waitable; h->read_pending->h = h; if (!ReadFile(h->h, target, target_space, &bytes, &h->read_pending->olap)) { DWORD err = GetLastError(); if (err != ERROR_IO_PENDING) { free(h->read_pending); h->read_pending = NULL; stream_debug("olap read failed immediately: %s\n", win32_strerror(err)); } else { stream_debug("olap read queued ok\n"); } stream_debug("returning %d\n", total_read == 0 ? -1 : total_read); errno = map_win32_err(err); return total_read == 0 ? -1 : total_read; } stream_debug("olap read succeeded immediately!? bytes=%d\n", (int)bytes); // We don't expect this to succeed in the overlapped case, // but we can handle the result anyway h->read_avail += bytes; free(h->read_pending); h->read_pending = NULL; move_from_read_buffer(h, &total_read, &buf, &size); stream_debug("read returning %d\n", total_read); return total_read; }
static bool win_read_handle_completion(struct win_handle *h) { BOOL olap_res; DWORD bytes, err; EnterCriticalSection(&h->mtx); if (!h->read_pending) { LeaveCriticalSection(&h->mtx); return false; } stream_debug("have read_pending, checking status\n"); // Don't hold the mutex while we're blocked LeaveCriticalSection(&h->mtx); olap_res = get_overlapped_result_ex(h->h, &h->read_pending->olap, &bytes, h->blocking ? INFINITE : 0, true); err = GetLastError(); EnterCriticalSection(&h->mtx); if (olap_res) { stream_debug("pending read completed, read %d bytes, %s\n", (int)bytes, win32_strerror(err)); h->read_avail += bytes; free(h->read_pending); h->read_pending = NULL; } else { stream_debug("pending read failed: %s\n", win32_strerror(err)); if (err != ERROR_IO_INCOMPLETE) { // Failed free(h->read_pending); h->read_pending = NULL; h->errcode = err; h->error_pending = true; } } LeaveCriticalSection(&h->mtx); return h->read_pending != NULL; }