2 * by Richard W.M. Jones <rich@annexia.org>
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the Free
16 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 * $Id: pthr_wait_queue.c,v 1.5 2002/12/01 14:29:30 rich Exp $
41 #include "pthr_pseudothread.h"
42 #include "pthr_wait_queue.h"
44 /* See implementation notes in <pthr_wait_queue.h>. */
47 /* List of threads currently sleeping on the queue. */
52 new_wait_queue (pool pool)
54 wait_queue wq = pmalloc (pool, sizeof *wq);
56 wq->sleepers = new_vector (pool, pseudothread);
61 wq_nr_sleepers (wait_queue wq)
63 return vector_size (wq->sleepers);
66 /* To sleep on the wait queue, we register ourselves, then we swap back
67 * into the reactor context.
70 wq_sleep_on (wait_queue wq)
72 vector_push_back (wq->sleepers, current_pth);
74 /* Swap context back to the calling context. */
75 _pth_switch_thread_to_calling_context ();
77 /* When we get here, we have been woken up ... */
79 /* Have we been signalled? */
80 if (_pth_alarm_received ())
85 /* Remove self from sleepers list. */
86 for (i = 0; i < vector_size (wq->sleepers); ++i)
88 vector_get (wq->sleepers, i, p);
91 vector_erase (wq->sleepers, i);
96 /* Oops - not found on sleepers list. */
105 /* This is the prepoll handler which actually wakes up the threads. */
109 vector sleepers; /* Pseudothreads to wake up. */
110 reactor_prepoll handler; /* Handler (must be unregistered at end). */
114 do_wake_up (void *infop)
116 struct wake_up_info *info = (struct wake_up_info *) infop;
119 for (i = 0; i < vector_size (info->sleepers); ++i)
123 vector_get (info->sleepers, i, pth);
125 /* Swap into the thread context. */
126 _pth_switch_calling_to_thread_context (pth);
129 reactor_unregister_prepoll (info->handler);
130 delete_pool (info->pool);
133 /* To wake up we take a private copy of the wait queue, clear the
134 * sleepers list, then register a prepoll handler which will eventually
135 * run and wake up each sleeper in turn.
138 wake_up (wait_queue wq, int n)
142 reactor_prepoll handler;
143 struct wake_up_info *wake_up_info;
145 /* Added this experimentally to get around a bug when rws running monolith
146 * apps which have database connections open is killed. It seems to be
147 * something to do with having prepoll handlers registered when the
148 * reactor exits. Avoid this entirely here - there is no need, as far as
149 * I can see, to do anything in this function if no one is actually sleeping
153 if (vector_size (wq->sleepers) == 0) return;
155 /* This will be freed up by the prepoll handler. */
156 pool = new_subpool (global_pool);
158 /* Take a private copy, either of the whole queue, or just part of it,
159 * and also clear the list.
163 v = copy_vector (pool, wq->sleepers);
164 vector_clear (wq->sleepers);
168 v = new_vector (pool, pseudothread);
174 vector_pop_front (wq->sleepers, pth);
175 vector_push_back (v, pth);
180 /* Register a prepoll handler to wake up these sleepin' bewts. */
181 wake_up_info = pmalloc (pool, sizeof *wake_up_info);
182 wake_up_info->pool = pool;
183 wake_up_info->sleepers = v;
184 handler = reactor_register_prepoll (pool, do_wake_up, wake_up_info);
185 wake_up_info->handler = handler;
189 wq_wake_up (wait_queue wq)
195 wq_wake_up_one (wait_queue wq)
197 /* If there is nothing on the wait queue, but we were instructed to
198 * wake one, then there is probably a bug in the code.
200 if (vector_size (wq->sleepers) < 1) abort ();