Add to git.
[pthrlib.git] / src / pthr_pseudothread.c
1 /* Pseudothread handler.
2  *
3  * This library is free software; you can redistribute it and/or
4  * modify it under the terms of the GNU Library General Public
5  * License as published by the Free Software Foundation; either
6  * version 2 of the License, or (at your option) any later version.
7  *
8  * This library is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11  * Library General Public License for more details.
12  *
13  * You should have received a copy of the GNU Library General Public
14  * License along with this library; if not, write to the Free
15  * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
16  *
17  * $Id: pthr_pseudothread.c,v 1.22 2003/02/05 22:13:32 rich Exp $
18  */
19
20 #include "config.h"
21
22 #include <stdio.h>
23 #include <stdlib.h>
24
25 #ifdef HAVE_ASSERT_H
26 #include <assert.h>
27 #endif
28
29 #ifdef HAVE_UNISTD_H
30 #include <unistd.h>
31 #endif
32
33 #ifdef HAVE_SETJMP_H
34 #include <setjmp.h>
35 #endif
36
37 #ifdef HAVE_ERRNO_H
38 #include <errno.h>
39 #endif
40
41 #ifdef HAVE_STRING_H
42 #include <string.h>
43 #endif
44
45 #ifdef HAVE_SYS_TYPES_H
46 #include <sys/types.h>
47 #endif
48
49 #ifdef HAVE_SYS_SOCKET_H
50 #include <sys/socket.h>
51 #endif
52
53 #ifdef HAVE_SYS_TIME_H
54 #include <sys/time.h>
55 #endif
56
57 #include <pool.h>
58 #include <vector.h>
59 #include <pstring.h>
60
61 #include "pthr_reactor.h"
62 #include "pthr_context.h"
63 #include "pthr_stack.h"
64 #include "pthr_pseudothread.h"
65
66 struct pseudothread
67 {
68   /* Thread context and calling (reactor) context. */
69   mctx_t thread_ctx, calling_ctx;
70
71   /* Thread number. */
72   int n;
73
74   /* Pointer to thread stack and size. */
75   void *stack;
76   int stack_size;
77
78   /* Alarm handling. */
79   int alarm_received;
80   reactor_timer alarm_timer;
81
82   /* Pool for memory allocations in this thread. */
83   pool pool;
84
85   /* Name of the thread. */
86   const char *name;
87
88   /* Used to implement pth_exit. */
89   jmp_buf exit_jmp;
90
91   /* Used to implement pth_die. */
92   vector exception_jmp_vec;
93   const char *exception_msg;
94
95   /* Used to implement pth_poll, pth_select. */
96   int poll_timeout;
97
98   /* Start point and data for thread. */
99   void (*run) (void *);
100   void *data;
101
102   /* LANGUAGE environment variable for this thread. If null, then
103    * the variable is unset in the thread.
104    */
105   const char *lang;
106
107   /* TZ environment variable for this thread. If null, then the
108    * variable is unset in the thread.
109    */
110   const char *tz;
111 };
112
113 /* Currently running pseudothread. */
114 pseudothread current_pth = 0;
115
116 /* Global list of threads. */
117 static vector threads = 0;
118
119 /* Default stack size, in bytes. */
120 static int default_stack_size = 65536;
121
122 static void block (int sock, int ops);
123 static void return_from_block (int sock, int events, void *);
124 static void _sleep (int timeout);
125 static void return_from_sleep (void *);
126 static void _poll (struct pollfd *fds, unsigned int n, int timeout);
127 static void return_from_poll (int sock, int events, void *);
128 static void return_from_poll_timeout (void *);
129 static void return_from_alarm (void *);
130
131 static void thread_trampoline (void *vpth);
132
133 static void pseudothread_init (void) __attribute__ ((constructor));
134
135 static void
136 pseudothread_init ()
137 {
138 #ifdef __OpenBSD__
139   /* OpenBSD doesn't call constructors in the correct order. */
140   pool global_pool = new_pool ();
141 #endif
142   threads = new_vector (global_pool, struct pseudothread *);
143 }
144
145 int
146 pseudothread_set_stack_size (int size)
147 {
148   return default_stack_size = size;
149 }
150
151 int
152 pseudothread_get_stack_size (void)
153 {
154   return default_stack_size;
155 }
156
157 pseudothread
158 new_pseudothread (pool pool,
159                   void (*run) (void *), void *data,
160                   const char *name)
161 {
162   pseudothread pth;
163   void *stack_addr;
164   int i;
165
166   /* Allocate space for the pseudothread. */
167   pth = pcalloc (pool, 1, sizeof *pth);
168
169   pth->run = run;
170   pth->data = data;
171   pth->pool = pool;
172   pth->name = name;
173
174   /* Create a stack for this thread. */
175   stack_addr = _pth_get_stack (default_stack_size);
176   if (stack_addr == 0) abort ();
177   pth->stack = stack_addr;
178   pth->stack_size = default_stack_size;
179
180   /* Create a new thread context. */
181   mctx_set (&pth->thread_ctx,
182             thread_trampoline, pth,
183             stack_addr, default_stack_size);
184
185   /* Allocate space in the global threads list for this thread. */
186   for (i = 0; i < vector_size (threads); ++i)
187     {
188       pseudothread p;
189
190       vector_get (threads, i, p);
191       if (p == 0)
192         {
193           pth->n = i;
194           vector_replace (threads, i, pth);
195           goto done;
196         }
197     }
198
199   pth->n = i;
200   vector_push_back (threads, pth);
201
202  done:
203   return pth;
204 }
205
206 static void
207 thread_trampoline (void *vpth)
208 {
209   pseudothread pth = (pseudothread) vpth;
210   mctx_t calling_ctx;
211   void *stack;
212   int stack_size;
213   const struct pseudothread *null_thread = 0;
214
215   /* Set up the current_pth before running user code. */
216   current_pth = pth;
217
218   if (setjmp (pth->exit_jmp) == 0)
219     pth->run (pth->data);
220
221   /* We return here either when "run" finishes normally or after
222    * a longjmp caused by the pseudothread calling pth_exit.
223    */
224
225   calling_ctx = pth->calling_ctx;
226
227   /* Remove the thread from the list of threads. */
228   vector_replace (threads, pth->n, null_thread);
229
230   /* Delete the pool and the stack. */
231   stack = pth->stack;
232   stack_size = pth->stack_size;
233   delete_pool (pth->pool);
234   _pth_return_stack (stack, stack_size);
235
236   /* Restore calling context (this never returns ...). */
237   mctx_restore (&calling_ctx);
238 }
239
240 void
241 pth_start (pseudothread pth)
242 {
243   pseudothread old_pth = current_pth;
244
245   /* Swap into the new context -- this actually calls thread_trampoline. */
246   mctx_switch (&pth->calling_ctx, &pth->thread_ctx);
247
248   /* Restore current_pth before returning into user code. */
249   current_pth = old_pth;
250 }
251
252 void
253 pth_set_name (const char *name)
254 {
255   current_pth->name = name;
256 }
257
258 const char *
259 pth_get_name (pseudothread pth)
260 {
261   return pth->name;
262 }
263
264 int
265 pth_get_thread_num (pseudothread pth)
266 {
267   return pth->n;
268 }
269
270 void
271 (*pth_get_run (pseudothread pth)) (void *)
272 {
273   return pth->run;
274 }
275
276 void *
277 pth_get_data (pseudothread pth)
278 {
279   return pth->data;
280 }
281
282 const char *
283 pth_get_language (pseudothread pth)
284 {
285   return pth->lang;
286 }
287
288 const char *
289 pth_get_tz (pseudothread pth)
290 {
291   return pth->tz;
292 }
293
294 void *
295 pth_get_stack (pseudothread pth)
296 {
297   return pth->stack;
298 }
299
300 int
301 pth_get_stack_size (pseudothread pth)
302 {
303   return pth->stack_size;
304 }
305
306 unsigned long
307 pth_get_PC (pseudothread pth)
308 {
309   return mctx_get_PC (&pth->thread_ctx);
310 }
311
312 unsigned long
313 pth_get_SP (pseudothread pth)
314 {
315   return mctx_get_SP (&pth->thread_ctx);
316 }
317
318 void
319 pth_exit ()
320 {
321   longjmp (current_pth->exit_jmp, 1);
322 }
323
324 const char *
325 pth_catch (void (*fn) (void *), void *data)
326 {
327   jmp_buf jb;
328
329   if (setjmp (jb) == 0)
330     {
331       /* Register the exception handler. */
332       if (current_pth->exception_jmp_vec == 0)
333         current_pth->exception_jmp_vec
334           = new_vector (current_pth->pool, jmp_buf);
335       vector_push_back (current_pth->exception_jmp_vec, jb);
336
337       /* Run the function. */
338       fn (data);
339
340       /* No errors: pop the exception handler. */
341       vector_pop_back (current_pth->exception_jmp_vec, jb);
342
343       return 0;
344     }
345
346   /* Exception was fired off. Return the message. */
347   return current_pth->exception_msg;
348 }
349
350 void
351 _pth_die (const char *msg, const char *filename, int lineno)
352 {
353   /* If there is a surrounding exception handler registered, then
354    * jump directly to it.
355    */
356   if (current_pth->exception_jmp_vec &&
357       vector_size (current_pth->exception_jmp_vec) > 0)
358     {
359       jmp_buf jb;
360
361       current_pth->exception_msg = msg;
362       vector_pop_back (current_pth->exception_jmp_vec, jb);
363       longjmp (jb, 1);
364       /*NOTREACHED*/
365     }
366
367   /* Otherwise: print the message and exit the pseudothread immediately. */
368   fprintf (stderr, "%s:%d: %s\n", filename, lineno, msg);
369   pth_exit ();
370 }
371
372 pool
373 pth_get_pool (pseudothread pth)
374 {
375   return pth->pool;
376 }
377
378 int
379 pth_accept (int s, struct sockaddr *addr, int *size)
380 {
381   int r;
382
383   do
384     {
385       block (s, REACTOR_READ);
386
387       /* Accept the connection. */
388       r = accept (s, addr, size);
389     }
390   while (r == -1 && errno == EWOULDBLOCK);
391
392   return r;
393 }
394
395 int
396 pth_connect (int s, struct sockaddr *addr, int size)
397 {
398   int r, sz;
399
400   /* Connect (NB. The socket had better have been set to non-blocking) */
401   r = connect (s, addr, size);
402
403   if (r == 0) return 0;         /* Connected immediately. */
404   else
405     {
406       if (errno == EINPROGRESS)
407         {
408           /* Wait for the socket to connect. */
409           block (s, REACTOR_WRITE);
410
411           /* Read the error code (see connect(2) man page for details). */
412           sz = sizeof r;
413           if (getsockopt (s, SOL_SOCKET, SO_ERROR, &r, &sz) < 0)
414             return -1;
415
416           /* What is the error code? */
417           errno = r;
418           return r == 0 ? 0 : -1;
419         }
420       else
421         {
422           /* Some other type of error before blocking. */
423           return -1;
424         }
425     }
426 }
427
428 ssize_t
429 pth_read (int s, void *buf, size_t count)
430 {
431   int r;
432
433  again:
434   r = read (s, buf, count);
435   if (r == -1 && errno == EWOULDBLOCK)
436     {
437       block (s, REACTOR_READ);
438       goto again;
439     }
440
441   return r;
442 }
443
444 ssize_t
445 pth_write (int s, const void *buf, size_t count)
446 {
447   int r;
448
449  again:
450   r = write (s, buf, count);
451   if (r == -1 && errno == EWOULDBLOCK)
452     {
453       block (s, REACTOR_WRITE);
454       goto again;
455     }
456
457   return r;
458 }
459
460 int
461 pth_sleep (int seconds)
462 {
463   _sleep (seconds * 1000);
464   return seconds;
465 }
466
467 int
468 pth_nanosleep (const struct timespec *req,
469                struct timespec *rem)
470 {
471   int timeout = req->tv_sec * 1000 + req->tv_nsec / 1000000;
472
473   _sleep (timeout);
474   return 0;
475 }
476
477 int
478 pth_millisleep (int millis)
479 {
480   _sleep (millis);
481   return 0;
482 }
483
484 void
485 pth_timeout (int seconds)
486 {
487   /* Unregister any previously registered alarm. */
488   if (current_pth->alarm_timer)
489     reactor_unset_timer_early (current_pth->alarm_timer);
490   current_pth->alarm_timer = 0;
491
492   if (seconds != 0)
493     current_pth->alarm_timer =
494       reactor_set_timer (current_pth->pool, seconds * 1000,
495                          return_from_alarm, current_pth);
496 }
497
498 int
499 pth_send (int s, const void *msg, int len, unsigned int flags)
500 {
501   int r;
502
503  again:
504   r = send (s, msg, len, flags);
505   if (r == -1 && errno == EWOULDBLOCK)
506     {
507       block (s, REACTOR_WRITE);
508       goto again;
509     }
510
511   return r;
512 }
513
514 int
515 pth_sendto (int s, const void *msg, int len, unsigned int flags,
516             const struct sockaddr *to, int tolen)
517 {
518   int r;
519
520  again:
521   r = sendto (s, msg, len, flags, to, tolen);
522   if (r == -1 && errno == EWOULDBLOCK)
523     {
524       block (s, REACTOR_WRITE);
525       goto again;
526     }
527
528   return r;
529 }
530
531 int
532 pth_sendmsg (int s, const struct msghdr *msg, unsigned int flags)
533 {
534   int r;
535
536  again:
537   r = sendmsg (s, msg, flags);
538   if (r == -1 && errno == EWOULDBLOCK)
539     {
540       block (s, REACTOR_WRITE);
541       goto again;
542     }
543
544   return r;
545 }
546
547 int
548 pth_recv (int s, void *buf, int len, unsigned int flags)
549 {
550   int r;
551
552  again:
553   r = recv (s, buf, len, flags);
554   if (r == -1 && errno == EWOULDBLOCK)
555     {
556       block (s, REACTOR_READ);
557       goto again;
558     }
559
560   return r;
561 }
562
563 int
564 pth_recvfrom (int s, void *buf, int len, unsigned int flags,
565               struct sockaddr *from, int *fromlen)
566 {
567   int r;
568
569  again:
570   r = recvfrom (s, buf, len, flags, from, fromlen);
571   if (r == -1 && errno == EWOULDBLOCK)
572     {
573       block (s, REACTOR_READ);
574       goto again;
575     }
576
577   return r;
578 }
579
580 int
581 pth_recvmsg (int s, struct msghdr *msg, unsigned int flags)
582 {
583   int r;
584
585  again:
586   r = recvmsg (s, msg, flags);
587   if (r == -1 && errno == EWOULDBLOCK)
588     {
589       block (s, REACTOR_READ);
590       goto again;
591     }
592
593   return r;
594 }
595
596 /* NB. Although it may appear that this version of poll is
597  * inefficient because it makes extra real poll(2) system calls,
598  * in the case where there are many fds being polled, and they
599  * are frequently ready (ie. high load cases ...), this will
600  * be much more efficient than alternatives.
601  */
602 int
603 pth_poll (struct pollfd *fds, unsigned int n, int timeout)
604 {
605   int r;
606
607  again:
608   r = poll (fds, n, 0);
609   if (r == 0)
610     {
611       _poll (fds, n, timeout);
612       if (current_pth->poll_timeout) return 0;
613       goto again;
614     }
615
616   return r;
617 }
618
619 /* Select is inefficiently implemented just as a library on top of
620  * the pth_poll call. Rewrite your code so it doesn't use pth_select.
621  */
622 int
623 pth_select (int n, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
624             struct timeval *timeout)
625 {
626   pool p = new_subpool (current_pth->pool);
627   vector v = new_vector (p, struct pollfd);
628   int i, to, r;
629   struct pollfd pfd, *fds;
630
631   /* Convert the sets into an array of poll descriptors. */
632   for (i = 0; i < n; ++i)
633     {
634       if (readfds && FD_ISSET (i, readfds))
635         {
636           pfd.fd = i;
637           pfd.events = POLLIN;
638           pfd.revents = 0;
639           vector_push_back (v, pfd);
640         }
641       if (writefds && FD_ISSET (i, writefds))
642         {
643           pfd.fd = i;
644           pfd.events = POLLOUT;
645           pfd.revents = 0;
646           vector_push_back (v, pfd);
647         }
648       if (exceptfds && FD_ISSET (i, exceptfds))
649         {
650           pfd.fd = i;
651           pfd.events = POLLERR;
652           pfd.revents = 0;
653           vector_push_back (v, pfd);
654         }
655     }
656
657   /* Call the underlying poll function. */
658   to = timeout ? timeout->tv_sec * 1000 + timeout->tv_usec / 1000 : -1;
659   vector_get_ptr (v, 0, fds);
660   n = vector_size (v);
661
662   r = pth_poll (fds, n, to);
663
664   /* Error. */
665   if (r == -1)
666     {
667       delete_pool (p);
668       return -1;
669     }
670
671   if (readfds) FD_ZERO (readfds);
672   if (writefds) FD_ZERO (writefds);
673   if (exceptfds) FD_ZERO (exceptfds);
674
675   /* Timeout. */
676   if (r == 0)
677     {
678       delete_pool (p);
679       return 0;
680     }
681
682   /* Convert the returned events into sets. */
683   for (i = 0; i < n; ++i)
684     {
685       if (fds[i].revents & POLLIN)
686         FD_SET (fds[i].fd, readfds);
687       if (fds[i].revents & POLLOUT)
688         FD_SET (fds[i].fd, writefds);
689       if (fds[i].revents & POLLERR)
690         FD_SET (fds[i].fd, exceptfds);
691     }
692
693   delete_pool (p);
694   return r;
695 }
696
697 int
698 pth_wait_readable (int fd)
699 {
700   int r;
701   struct pollfd fds[1];
702
703   fds[0].fd = fd;
704   fds[0].events = POLLIN;
705   fds[0].revents = 0;           /* Don't care. */
706
707  again:
708   r = poll (fds, 1, -1);
709   if (r == 0)
710     {
711       block (fd, REACTOR_READ);
712       goto again;
713     }
714
715   return r >= 0 ? 1 : -1;
716 }
717
718 int
719 pth_wait_writable (int fd)
720 {
721   int r;
722   struct pollfd fds[1];
723
724   fds[0].fd = fd;
725   fds[0].events = POLLOUT;
726   fds[0].revents = 0;           /* Don't care. */
727
728  again:
729   r = poll (fds, 1, -1);
730   if (r == 0)
731     {
732       block (fd, REACTOR_WRITE);
733       goto again;
734     }
735
736   return r >= 0 ? 1 : -1;
737 }
738
739 #if defined(HAVE_SETENV) && defined(HAVE_UNSETENV)
740 #define do_setenv(name,value) setenv ((name), (value), 1)
741 #define do_unsetenv(name) unsetenv ((name))
742 #elif defined(HAVE_PUTENV)
743 /* This implementation is ugly, but then putenv is an ugly function. */
744
745 /* This array maps environment variable names to the 'putenv'-ed env
746  * string. First time round we add a new env string to this array and
747  * putenv it into the environment. Subsequently we modify the env
748  * string.
749  */
750 static struct putenv_map {
751   struct putenv_map *next;
752   const char *name;
753   char env[256];
754 } *putenv_map = 0;
755
756 static inline void
757 do_setenv (const char *name, const char *value)
758 {
759   struct putenv_map *m;
760
761   for (m = putenv_map; m; m = m->next)
762     if (strcmp (m->name, name) == 0)
763       {
764         /* Modify the env in-place. */
765       finish:
766         snprintf (m->env, sizeof m->env, "%s=%s", name, value);
767         putenv (m->env);
768         return;
769       }
770
771   /* Create a new entry. */
772   m = pmalloc (global_pool, sizeof *m);
773   m->next = putenv_map;
774   m->name = name;
775   goto finish;
776 }
777
778 #define do_unsetenv(name) putenv ((name))
779
780 #else
781 #error "no setenv/unsetenv or putenv in your libc"
782 #endif
783
784 static inline void
785 _restore_lang ()
786 {
787   if (current_pth->lang == 0)
788     do_unsetenv ("LANGUAGE");
789   else
790     do_setenv ("LANGUAGE", current_pth->lang);
791
792 #ifdef __GLIBC__
793   {
794     /* Please see gettext info file, node ``Being a `gettext' grok'', section
795      * ``Changing the language at runtime''.
796      */
797     extern int _nl_msg_cat_cntr;
798     _nl_msg_cat_cntr++;
799   }
800 #endif
801 }
802
803 static inline void
804 _restore_tz ()
805 {
806   if (current_pth->tz == 0)
807     do_unsetenv ("TZ");
808   else
809     do_setenv ("TZ", current_pth->tz);
810 }
811
812 void
813 pth_set_language (const char *lang)
814 {
815   current_pth->lang = pstrdup (current_pth->pool, lang);
816   _restore_lang ();
817 }
818
819 void
820 pth_set_tz (const char *tz)
821 {
822   current_pth->tz = pstrdup (current_pth->pool, tz);
823   _restore_tz ();
824 }
825
826 inline void
827 _pth_switch_thread_to_calling_context ()
828 {
829   mctx_switch (&current_pth->thread_ctx, &current_pth->calling_ctx);
830 }
831
832 inline void
833 _pth_switch_calling_to_thread_context (pseudothread pth)
834 {
835   current_pth = pth;            /* Set current thread. */
836   mctx_switch (&current_pth->calling_ctx, &current_pth->thread_ctx);
837 }
838
839 inline int
840 _pth_alarm_received ()
841 {
842   return current_pth->alarm_received;
843 }
844
845 static void
846 block (int sock, int operations)
847 {
848   /* Register a read event in the reactor. */
849   reactor_handle handle
850     = reactor_register (sock, operations, return_from_block, current_pth);
851
852   /* Swap context back to the calling context. */
853   _pth_switch_thread_to_calling_context ();
854
855   /* Unregister the handle. */
856   reactor_unregister (handle);
857
858   /* Received alarm signal? - Exit. */
859   if (_pth_alarm_received ())
860     pth_exit ();
861
862   /* Restore environment. */
863   _restore_lang ();
864   _restore_tz ();
865 }
866
867 static void
868 return_from_block (int sock, int events, void *vpth)
869 {
870   /* Swap back to the thread context. */
871   _pth_switch_calling_to_thread_context ((pseudothread) vpth);
872 }
873
874 static void
875 _sleep (int timeout)
876 {
877   /* Register a timer in the reactor. */
878   reactor_timer timer
879     = reactor_set_timer (current_pth->pool, timeout,
880                          return_from_sleep, current_pth);
881
882   /* Swap context back to the calling context. */
883   _pth_switch_thread_to_calling_context ();
884
885   /* Received alarm signal? - Exit. */
886   if (_pth_alarm_received ())
887     {
888       reactor_unset_timer_early (timer);
889       pth_exit ();
890     }
891
892   /* Note: no need to unregister the timer, since it has fired. */
893
894   /* Restore environment. */
895   _restore_lang ();
896   _restore_tz ();
897 }
898
899 static void
900 return_from_sleep (void *vpth)
901 {
902   /* Swap back to the thread context. */
903   _pth_switch_calling_to_thread_context ((pseudothread) vpth);
904 }
905
906 static void
907 _poll (struct pollfd *fds, unsigned int n, int timeout)
908 {
909   reactor_timer timer = 0;
910   reactor_handle handle[n];
911   int i;
912
913   (void) &timer;                /* Tell gcc not to put it in a register. */
914   current_pth->poll_timeout = 0;
915
916   /* Register all events in the reactor. */
917   for (i = 0; i < n; ++i)
918     /* NB: Poll operations == reactor operations. */
919     handle[i] = reactor_register (fds[i].fd, fds[i].events,
920                                   return_from_poll, current_pth);
921
922   /* Timeout? */
923   if (timeout >= 0)
924     timer = reactor_set_timer (current_pth->pool, timeout,
925                                return_from_poll_timeout, current_pth);
926
927   /* Swap context back to calling context. */
928   _pth_switch_thread_to_calling_context ();
929
930   /* Unregister all the handles. */
931   for (i = 0; i < n; ++i)
932     reactor_unregister (handle[i]);
933
934   /* Delete the timer, if it exists but hasn't fired. */
935   if (timer && !current_pth->poll_timeout)
936     reactor_unset_timer_early (timer);
937
938   /* Received alarm signal? Exit. */
939   if (_pth_alarm_received ())
940     pth_exit ();
941
942   /* Restore environment. */
943   _restore_lang ();
944   _restore_tz ();
945 }
946
947 static void
948 return_from_poll (int sock, int events, void *vpth)
949 {
950   /* Swap back to the thread context. */
951   _pth_switch_calling_to_thread_context ((pseudothread) vpth);
952 }
953
954 static void
955 return_from_poll_timeout (void *vpth)
956 {
957   pseudothread pth = (pseudothread) vpth;
958
959   pth->poll_timeout = 1;
960
961   /* Swap back to the thread context. */
962   _pth_switch_calling_to_thread_context (pth);
963 }
964
965 static void
966 return_from_alarm (void *vpth)
967 {
968   pseudothread pth = (pseudothread) vpth;
969
970   pth->alarm_received = 1;
971   pth->alarm_timer = 0;
972
973   /* Swap back to the thread context. */
974   _pth_switch_calling_to_thread_context (pth);
975 }
976
977 vector
978 pseudothread_get_threads (pool pool)
979 {
980   vector v = new_vector (pool, struct pseudothread);
981   int i;
982
983   for (i = 0; i < vector_size (threads); ++i)
984     {
985       pseudothread pth;
986       struct pseudothread pth_copy;
987
988       vector_get (threads, i, pth);
989
990       if (pth)
991         {
992           /* Perform a deep copy of the structure. */
993           memcpy (&pth_copy, pth, sizeof pth_copy);
994           if (pth_copy.name)
995             pth_copy.name = pstrdup (pool, pth_copy.name);
996           if (pth_copy.lang)
997             pth_copy.lang = pstrdup (pool, pth_copy.lang);
998           if (pth_copy.tz)
999             pth_copy.tz = pstrdup (pool, pth_copy.tz);
1000
1001           vector_push_back (v, pth_copy);
1002         }
1003     }
1004
1005   return v;
1006 }
1007
1008 int
1009 pseudothread_count_threads (void)
1010 {
1011   int count = 0;
1012   int i;
1013
1014   for (i = 0; i < vector_size (threads); ++i)
1015     {
1016       pseudothread pth;
1017
1018       vector_get (threads, i, pth);
1019
1020       if (pth) count++;
1021     }
1022
1023   return count;
1024 }