void copy_from_disk_queue_to_memory_queue(auto_drainer_t::lock_t keepalive) { try { while (!keepalive.get_drain_signal()->is_pulsed()) { if (disk_queue->empty()) { if (items_in_queue != memory_queue.size()) { // There is a push in progress, there's no good way to wait on it, so we'll start a new coroutine later restart_copy_coro = true; } else { disk_queue.reset(); } break; } T value; disk_queue->pop(&value); if (memory_queue.full()) { guarantee(notify_when_room_in_memory_queue == NULL); cond_t cond; assignment_sentry_t<cond_t *> assignment_sentry(¬ify_when_room_in_memory_queue, &cond); wait_interruptible(&cond, keepalive.get_drain_signal()); } memory_queue.push_back(value); available_control.set_available(true); } } catch (const interrupted_exc_t &) { /* ignore */ } }
void copy_from_disk_queue_to_memory_queue(auto_drainer_t::lock_t keepalive) { try { while (!keepalive.get_drain_signal()->is_pulsed()) { if (disk_queue->empty()) { if (items_in_queue != memory_queue.size()) { // There is a push in progress, there's no good way to wait on // it, so we'll start a new coroutine later restart_copy_coro = true; } else { disk_queue.reset(); } break; } write_message_t wm; copying_viewer_t viewer(&wm); disk_queue->pop(&viewer); if (memory_queue_free_space <= 0) { guarantee(notify_when_room_in_memory_queue == nullptr); cond_t cond; assignment_sentry_t<cond_t *> assignment_sentry( ¬ify_when_room_in_memory_queue, &cond); wait_interruptible(&cond, keepalive.get_drain_signal()); } memory_queue_free_space -= wm.size(); memory_queue.emplace_back(std::move(wm)); available_control.set_available(true); } } catch (const interrupted_exc_t &) { /* ignore */ } }
/* The purpose of `random_delay()` is to mix things up a bit to increase the likelihood of exposing a bug in `artificial_table_t`. */ void random_delay(signal_t *interruptor) { if (randint(2) == 0) { signal_timer_t timer; timer.start(randint(100)); wait_interruptible(&timer, interruptor); } }
/* * Wait until a buffer is unlocked. */ void buffer_wait(struct buffer *buf) { while (buf->b_lock) { wait_interruptible(&buf->b_wait); // TODO: handle signals } }
ssize_t pipe_read(struct file *file, char *dst, size_t len, unsigned long *pos) { ssize_t nr_bytes; struct pipe_private *pipe = file->f_private; while (!(nr_bytes = flexbuf_dequeue(pipe->buf, dst, len))) { // pipe is empty if (!pipe->write_end) return 0; // no writers: EOF if (file->f_flags & O_NONBLOCK) return -EAGAIN; if (wait_interruptible(&pipe->read_wait)) return -EINTR; } wake_all(&pipe->write_wait, 0); return nr_bytes; }
/* * Write @len bytes to @pipe atomically with respect to other writers. */ static ssize_t pipe_do_write(struct pipe_private *pipe, const char *src, size_t len) { size_t nr_bytes = 0; while (1) { // write as much as we can size_t this_len = MIN(len-nr_bytes, pipe_headroom(pipe)); size_t this_bytes = flexbuf_enqueue(&pipe->buf, src+nr_bytes, this_len); if (this_bytes) wake_all(&pipe->read_wait, 0); // termination condition in the middle of the loop... nr_bytes += this_bytes; if (nr_bytes == len) break; if (wait_interruptible(&pipe->write_wait)) return nr_bytes ? (ssize_t)nr_bytes : -EINTR; } return nr_bytes; }