diff options
-rw-r--r-- | console-client/kbd-repeat.c | 3 | ||||
-rw-r--r-- | console-client/pc-mouse.c | 3 | ||||
-rw-r--r-- | libpipe/pipe.c | 89 | ||||
-rw-r--r-- | libpipe/pipe.h | 9 | ||||
-rw-r--r-- | pfinet/tunnel.c | 2 | ||||
-rw-r--r-- | term/devio.c | 1 | ||||
-rw-r--r-- | term/hurdio.c | 1 | ||||
-rw-r--r-- | term/main.c | 2 | ||||
-rw-r--r-- | term/ptyio.c | 4 | ||||
-rw-r--r-- | term/term.h | 25 | ||||
-rw-r--r-- | trans/streamio.c | 15 |
11 files changed, 120 insertions, 34 deletions
diff --git a/console-client/kbd-repeat.c b/console-client/kbd-repeat.c index 4bf9268e..b9000b22 100644 --- a/console-client/kbd-repeat.c +++ b/console-client/kbd-repeat.c @@ -81,6 +81,7 @@ kbd_repeat_key (kd_event *key) memcpy (ev, key, sizeof (kd_event)); condition_broadcast (&kbdbuf.readcond); + condition_broadcast (&select_alert); mutex_unlock (&global_lock); } @@ -231,9 +232,7 @@ kbd_setrepeater (const char *nodename, consnode_t *cn) condition_init (&kbdbuf.readcond); condition_init (&kbdbuf.writecond); - condition_init (&select_alert); - condition_implies (&kbdbuf.readcond, &select_alert); console_register_consnode (*cn); diff --git a/console-client/pc-mouse.c b/console-client/pc-mouse.c index cf8987bf..8a9009fb 100644 --- a/console-client/pc-mouse.c +++ b/console-client/pc-mouse.c @@ -105,6 +105,7 @@ repeat_event (kd_event *evt) memcpy (ev, evt, sizeof (kd_event)); condition_broadcast (&mousebuf.readcond); + condition_broadcast (&select_alert); mutex_unlock (&global_lock); } @@ -499,9 +500,7 @@ setrepeater (const char *nodename) condition_init (&mousebuf.readcond); condition_init (&mousebuf.writecond); - condition_init (&select_alert); - condition_implies (&mousebuf.readcond, &select_alert); console_register_consnode (cnode); diff --git a/libpipe/pipe.c b/libpipe/pipe.c index 914816bc..85aac0e6 100644 --- a/libpipe/pipe.c +++ b/libpipe/pipe.c @@ -64,6 +64,7 @@ pipe_create (struct pipe_class *class, struct pipe **pipe) condition_init (&new->pending_read_selects); condition_init (&new->pending_writes); condition_init (&new->pending_write_selects); + new->pending_selects = NULL; mutex_init (&new->lock); pq_create (&new->queue); @@ -83,6 +84,63 @@ pipe_free (struct pipe *pipe) free (pipe); } +static void +pipe_add_select_cond (struct pipe *pipe, struct pipe_select_cond *cond) +{ + struct pipe_select_cond *first, *last; + + first = pipe->pending_selects; + + if (first == NULL) + { + cond->next = cond; + cond->prev = cond; + pipe->pending_selects = cond; + return; + } + + last = first->prev; + cond->next = first; + cond->prev = last; + first->prev = cond; + last->next = cond; +} + +static void +pipe_remove_select_cond (struct pipe *pipe, struct pipe_select_cond *cond) +{ + cond->prev->next = cond->next; + cond->next->prev = cond->prev; + + if (pipe->pending_selects == cond) + { + if (cond->next == cond) + pipe->pending_selects = NULL; + else + pipe->pending_selects = cond->next; + } +} + +static void +pipe_select_cond_broadcast (struct pipe *pipe) +{ + struct pipe_select_cond *cond, *last; + + cond = pipe->pending_selects; + + if (cond == NULL) + return; + + last = cond->prev; + + do + { + condition_broadcast (&cond->cond); + cond = cond->next; + } + while (cond != last); +} + /* Take any actions necessary when PIPE acquires its first writer. */ void _pipe_first_writer (struct pipe *pipe) { @@ -113,6 +171,7 @@ void _pipe_no_readers (struct pipe *pipe) { condition_broadcast (&pipe->pending_writes); condition_broadcast (&pipe->pending_write_selects); + pipe_select_cond_broadcast (pipe); } } mutex_unlock (&pipe->lock); @@ -135,6 +194,7 @@ void _pipe_no_writers (struct pipe *pipe) { condition_broadcast (&pipe->pending_reads); condition_broadcast (&pipe->pending_read_selects); + pipe_select_cond_broadcast (pipe); } } mutex_unlock (&pipe->lock); @@ -171,22 +231,22 @@ pipe_pair_select (struct pipe *rpipe, struct pipe *wpipe, /* ugh */ { int rpipe_blocked, wpipe_blocked; - struct condition pending_read_write_select; + struct pipe_select_cond pending_select; size_t wlimit = wpipe->write_limit; struct mutex *lock = (wpipe == rpipe ? &rpipe->lock : &pipe_multiple_lock); - condition_init (&pending_read_write_select); - condition_implies (&rpipe->pending_read_selects, - &pending_read_write_select); - condition_implies (&wpipe->pending_write_selects, - &pending_read_write_select); + condition_init (&pending_select.cond); mutex_lock (lock); - if (rpipe != wpipe) + if (rpipe == wpipe) + pipe_add_select_cond (rpipe, &pending_select); + else { mutex_lock (&rpipe->lock); mutex_lock (&wpipe->lock); + pipe_add_select_cond (rpipe, &pending_select); + pipe_add_select_cond (wpipe, &pending_select); } rpipe_blocked = @@ -200,7 +260,7 @@ pipe_pair_select (struct pipe *rpipe, struct pipe *wpipe, mutex_unlock (&rpipe->lock); mutex_unlock (&wpipe->lock); } - if (hurd_condition_wait (&pending_read_write_select, lock)) + if (hurd_condition_wait (&pending_select.cond, lock)) err = EINTR; if (rpipe != wpipe) { @@ -223,17 +283,16 @@ pipe_pair_select (struct pipe *rpipe, struct pipe *wpipe, *select_type &= ~SELECT_WRITE; } - if (rpipe != wpipe) + if (rpipe == wpipe) + pipe_remove_select_cond (rpipe, &pending_select); + else { + pipe_remove_select_cond (rpipe, &pending_select); + pipe_remove_select_cond (wpipe, &pending_select); mutex_unlock (&rpipe->lock); mutex_unlock (&wpipe->lock); } mutex_unlock (lock); - - condition_unimplies (&rpipe->pending_read_selects, - &pending_read_write_select); - condition_unimplies (&wpipe->pending_write_selects, - &pending_read_write_select); } return err; @@ -306,6 +365,7 @@ pipe_send (struct pipe *pipe, int noblock, void *source, if (pipe_is_readable (pipe, 0)) { condition_broadcast (&pipe->pending_read_selects); + pipe_select_cond_broadcast (pipe); /* We leave PIPE locked here, assuming the caller will soon unlock it and allow others access. */ } @@ -407,6 +467,7 @@ pipe_recv (struct pipe *pipe, int noblock, unsigned *flags, void **source, if (pipe_readable (pipe, 1) < pipe->write_limit) { condition_broadcast (&pipe->pending_write_selects); + pipe_select_cond_broadcast (pipe); /* We leave PIPE locked here, assuming the caller will soon unlock it and allow others access. */ } diff --git a/libpipe/pipe.h b/libpipe/pipe.h index 96432990..a3590fc4 100644 --- a/libpipe/pipe.h +++ b/libpipe/pipe.h @@ -62,6 +62,13 @@ extern struct pipe_class *stream_pipe_class; extern struct pipe_class *dgram_pipe_class; extern struct pipe_class *seqpack_pipe_class; +struct pipe_select_cond +{ + struct pipe_select_cond *next; + struct pipe_select_cond *prev; + struct condition cond; +}; + /* A unidirectional data pipe; it transfers data from READER to WRITER. */ struct pipe { @@ -88,6 +95,8 @@ struct pipe struct condition pending_writes; struct condition pending_write_selects; + struct pipe_select_cond *pending_selects; + /* The maximum number of characters that this pipe will hold without further writes blocking. */ size_t write_limit; diff --git a/pfinet/tunnel.c b/pfinet/tunnel.c index ec96861a..6f9e1498 100644 --- a/pfinet/tunnel.c +++ b/pfinet/tunnel.c @@ -135,6 +135,7 @@ tunnel_xmit (struct sk_buff *skb, struct device *dev) { tdev->read_blocked = 0; condition_broadcast (&tdev->wait); + condition_broadcast (&tdev->select_alert); } __mutex_unlock (&tdev->lock); @@ -213,7 +214,6 @@ setup_tunnel_device (char *name, struct device **device) __mutex_init (&tdev->lock); condition_init (&tdev->wait); condition_init (&tdev->select_alert); - condition_implies (&tdev->wait, &tdev->select_alert); /* This call adds the device to the `dev_base' chain, initializes its `ifindex' member (which matters!), diff --git a/term/devio.c b/term/devio.c index 38eb996c..8aa960b9 100644 --- a/term/devio.c +++ b/term/devio.c @@ -323,6 +323,7 @@ device_write_reply_inband (mach_port_t replypt, { npending_output = 0; condition_broadcast (outputq->wait); + condition_broadcast (&select_alert); } else { diff --git a/term/hurdio.c b/term/hurdio.c index ef34740b..b1d0c944 100644 --- a/term/hurdio.c +++ b/term/hurdio.c @@ -286,6 +286,7 @@ hurdio_writer_loop (any_t arg) { npending_output = 0; condition_broadcast (outputq->wait); + condition_broadcast (&select_alert); } else { diff --git a/term/main.c b/term/main.c index 405e7cd8..e15fee53 100644 --- a/term/main.c +++ b/term/main.c @@ -443,8 +443,6 @@ main (int argc, char **argv) condition_init (&carrier_alert); condition_init (&select_alert); - condition_implies (inputq->wait, &select_alert); - condition_implies (outputq->wait, &select_alert); /* Launch. */ ports_manage_port_operations_multithread (term_bucket, demuxer, 0, 0, 0); diff --git a/term/ptyio.c b/term/ptyio.c index 9c1509ff..b02cda3f 100644 --- a/term/ptyio.c +++ b/term/ptyio.c @@ -58,8 +58,7 @@ static int nptyperopens = 0; static error_t ptyio_init (void) { - condition_implies (inputq->wait, &pty_select_wakeup); - condition_implies (&pty_read_wakeup, &pty_select_wakeup); + pty_select_alert = &pty_select_wakeup; return 0; } @@ -132,6 +131,7 @@ wake_reader () { pty_read_blocked = 0; condition_broadcast (&pty_read_wakeup); + condition_broadcast (&pty_select_wakeup); } } diff --git a/term/term.h b/term/term.h index 81d0efee..2df20337 100644 --- a/term/term.h +++ b/term/term.h @@ -103,6 +103,9 @@ struct condition carrier_alert; /* Wakeup for select */ struct condition select_alert; +/* Wakeup for pty select, if not null */ +struct condition *pty_select_alert; + /* Bucket for all our ports. */ struct port_bucket *term_bucket; @@ -225,6 +228,9 @@ clear_queue (struct queue *q) q->susp = 0; q->cs = q->ce = q->array; condition_broadcast (q->wait); + condition_broadcast (&select_alert); + if (q == inputq && pty_select_alert != NULL) + condition_broadcast (pty_select_alert); } #endif /* Use extern inlines. */ @@ -249,7 +255,10 @@ dequeue_quote (struct queue *q) if (beep) { condition_broadcast (q->wait); - if (q == outputq) + condition_broadcast (&select_alert); + if (q == inputq && pty_select_alert != NULL) + condition_broadcast (pty_select_alert); + else if (q == outputq) call_asyncs (O_WRITE); } return *q->cs++; @@ -280,8 +289,13 @@ enqueue_internal (struct queue **qp, quoted_char c) if (qsize (q) == 1) { condition_broadcast (q->wait); + condition_broadcast (&select_alert); if (q == inputq) - call_asyncs (O_READ); + { + if (pty_select_alert != NULL) + condition_broadcast (pty_select_alert); + call_asyncs (O_READ); + } } if (!q->susp && (qsize (q) > q->hiwat)) @@ -334,7 +348,12 @@ queue_erase (struct queue *q) if (qsize (q) == 0) beep = 1; if (beep) - condition_broadcast (q->wait); + { + condition_broadcast (q->wait); + condition_broadcast (&select_alert); + if (q == inputq && pty_select_alert != NULL) + condition_broadcast (pty_select_alert); + } return answer; } #endif /* Use extern inlines. */ diff --git a/trans/streamio.c b/trans/streamio.c index c563c03c..9ced28b3 100644 --- a/trans/streamio.c +++ b/trans/streamio.c @@ -108,6 +108,7 @@ clear_buffer (struct buffer *b) return; b->head = b->tail = b->buf; condition_broadcast (b->wait); + condition_broadcast (&select_alert); } /* Read up to LEN bytes from B to DATA, returning the amount actually read. */ @@ -132,6 +133,7 @@ buffer_read (struct buffer *b, void *data, size_t len) } condition_broadcast (b->wait); + condition_broadcast (&select_alert); return len; } @@ -148,6 +150,7 @@ buffer_write (struct buffer *b, void *data, size_t len) b->tail += len; condition_broadcast (b->wait); + condition_broadcast (&select_alert); return len; } @@ -300,15 +303,9 @@ main (int argc, char *argv[]) condition_init (&select_alert); if (trivfs_allow_open & O_READ) - { - input_buffer = create_buffer (256); - condition_implies (input_buffer->wait, &select_alert); - } + input_buffer = create_buffer (256); if (trivfs_allow_open & O_WRITE) - { - output_buffer = create_buffer (256); - condition_implies (output_buffer->wait, &select_alert); - } + output_buffer = create_buffer (256); /* Launch */ ports_manage_port_operations_multithread (streamdev_bucket, demuxer, @@ -999,6 +996,7 @@ device_read_reply_inband (mach_port_t reply, error_t errorcode, data += nwritten; datalen -= nwritten; condition_broadcast (input_buffer->wait); + condition_broadcast (&select_alert); } } else @@ -1102,6 +1100,7 @@ device_write_reply_inband (mach_port_t reply, error_t returncode, int amount) { npending_output = 0; condition_broadcast (output_buffer->wait); + condition_broadcast (&select_alert); } else { |