1 /* Pseudothread handler.
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.
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.
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.
17 * $Id: pthr_pseudothread.c,v 1.22 2003/02/05 22:13:32 rich Exp $
45 #ifdef HAVE_SYS_TYPES_H
46 #include <sys/types.h>
49 #ifdef HAVE_SYS_SOCKET_H
50 #include <sys/socket.h>
53 #ifdef HAVE_SYS_TIME_H
61 #include "pthr_reactor.h"
62 #include "pthr_context.h"
63 #include "pthr_stack.h"
64 #include "pthr_pseudothread.h"
68 /* Thread context and calling (reactor) context. */
69 mctx_t thread_ctx, calling_ctx;
74 /* Pointer to thread stack and size. */
80 reactor_timer alarm_timer;
82 /* Pool for memory allocations in this thread. */
85 /* Name of the thread. */
88 /* Used to implement pth_exit. */
91 /* Used to implement pth_die. */
92 vector exception_jmp_vec;
93 const char *exception_msg;
95 /* Used to implement pth_poll, pth_select. */
98 /* Start point and data for thread. */
102 /* LANGUAGE environment variable for this thread. If null, then
103 * the variable is unset in the thread.
107 /* TZ environment variable for this thread. If null, then the
108 * variable is unset in the thread.
113 /* Currently running pseudothread. */
114 pseudothread current_pth = 0;
116 /* Global list of threads. */
117 static vector threads = 0;
119 /* Default stack size, in bytes. */
120 static int default_stack_size = 65536;
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 *);
131 static void thread_trampoline (void *vpth);
133 static void pseudothread_init (void) __attribute__ ((constructor));
139 /* OpenBSD doesn't call constructors in the correct order. */
140 pool global_pool = new_pool ();
142 threads = new_vector (global_pool, struct pseudothread *);
146 pseudothread_set_stack_size (int size)
148 return default_stack_size = size;
152 pseudothread_get_stack_size (void)
154 return default_stack_size;
158 new_pseudothread (pool pool,
159 void (*run) (void *), void *data,
166 /* Allocate space for the pseudothread. */
167 pth = pcalloc (pool, 1, sizeof *pth);
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;
180 /* Create a new thread context. */
181 mctx_set (&pth->thread_ctx,
182 thread_trampoline, pth,
183 stack_addr, default_stack_size);
185 /* Allocate space in the global threads list for this thread. */
186 for (i = 0; i < vector_size (threads); ++i)
190 vector_get (threads, i, p);
194 vector_replace (threads, i, pth);
200 vector_push_back (threads, pth);
207 thread_trampoline (void *vpth)
209 pseudothread pth = (pseudothread) vpth;
213 const struct pseudothread *null_thread = 0;
215 /* Set up the current_pth before running user code. */
218 if (setjmp (pth->exit_jmp) == 0)
219 pth->run (pth->data);
221 /* We return here either when "run" finishes normally or after
222 * a longjmp caused by the pseudothread calling pth_exit.
225 calling_ctx = pth->calling_ctx;
227 /* Remove the thread from the list of threads. */
228 vector_replace (threads, pth->n, null_thread);
230 /* Delete the pool and the stack. */
232 stack_size = pth->stack_size;
233 delete_pool (pth->pool);
234 _pth_return_stack (stack, stack_size);
236 /* Restore calling context (this never returns ...). */
237 mctx_restore (&calling_ctx);
241 pth_start (pseudothread pth)
243 pseudothread old_pth = current_pth;
245 /* Swap into the new context -- this actually calls thread_trampoline. */
246 mctx_switch (&pth->calling_ctx, &pth->thread_ctx);
248 /* Restore current_pth before returning into user code. */
249 current_pth = old_pth;
253 pth_set_name (const char *name)
255 current_pth->name = name;
259 pth_get_name (pseudothread pth)
265 pth_get_thread_num (pseudothread pth)
271 (*pth_get_run (pseudothread pth)) (void *)
277 pth_get_data (pseudothread pth)
283 pth_get_language (pseudothread pth)
289 pth_get_tz (pseudothread pth)
295 pth_get_stack (pseudothread pth)
301 pth_get_stack_size (pseudothread pth)
303 return pth->stack_size;
307 pth_get_PC (pseudothread pth)
309 return mctx_get_PC (&pth->thread_ctx);
313 pth_get_SP (pseudothread pth)
315 return mctx_get_SP (&pth->thread_ctx);
321 longjmp (current_pth->exit_jmp, 1);
325 pth_catch (void (*fn) (void *), void *data)
329 if (setjmp (jb) == 0)
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);
337 /* Run the function. */
340 /* No errors: pop the exception handler. */
341 vector_pop_back (current_pth->exception_jmp_vec, jb);
346 /* Exception was fired off. Return the message. */
347 return current_pth->exception_msg;
351 _pth_die (const char *msg, const char *filename, int lineno)
353 /* If there is a surrounding exception handler registered, then
354 * jump directly to it.
356 if (current_pth->exception_jmp_vec &&
357 vector_size (current_pth->exception_jmp_vec) > 0)
361 current_pth->exception_msg = msg;
362 vector_pop_back (current_pth->exception_jmp_vec, jb);
367 /* Otherwise: print the message and exit the pseudothread immediately. */
368 fprintf (stderr, "%s:%d: %s\n", filename, lineno, msg);
373 pth_get_pool (pseudothread pth)
379 pth_accept (int s, struct sockaddr *addr, int *size)
385 block (s, REACTOR_READ);
387 /* Accept the connection. */
388 r = accept (s, addr, size);
390 while (r == -1 && errno == EWOULDBLOCK);
396 pth_connect (int s, struct sockaddr *addr, int size)
400 /* Connect (NB. The socket had better have been set to non-blocking) */
401 r = connect (s, addr, size);
403 if (r == 0) return 0; /* Connected immediately. */
406 if (errno == EINPROGRESS)
408 /* Wait for the socket to connect. */
409 block (s, REACTOR_WRITE);
411 /* Read the error code (see connect(2) man page for details). */
413 if (getsockopt (s, SOL_SOCKET, SO_ERROR, &r, &sz) < 0)
416 /* What is the error code? */
418 return r == 0 ? 0 : -1;
422 /* Some other type of error before blocking. */
429 pth_read (int s, void *buf, size_t count)
434 r = read (s, buf, count);
435 if (r == -1 && errno == EWOULDBLOCK)
437 block (s, REACTOR_READ);
445 pth_write (int s, const void *buf, size_t count)
450 r = write (s, buf, count);
451 if (r == -1 && errno == EWOULDBLOCK)
453 block (s, REACTOR_WRITE);
461 pth_sleep (int seconds)
463 _sleep (seconds * 1000);
468 pth_nanosleep (const struct timespec *req,
469 struct timespec *rem)
471 int timeout = req->tv_sec * 1000 + req->tv_nsec / 1000000;
478 pth_millisleep (int millis)
485 pth_timeout (int seconds)
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;
493 current_pth->alarm_timer =
494 reactor_set_timer (current_pth->pool, seconds * 1000,
495 return_from_alarm, current_pth);
499 pth_send (int s, const void *msg, int len, unsigned int flags)
504 r = send (s, msg, len, flags);
505 if (r == -1 && errno == EWOULDBLOCK)
507 block (s, REACTOR_WRITE);
515 pth_sendto (int s, const void *msg, int len, unsigned int flags,
516 const struct sockaddr *to, int tolen)
521 r = sendto (s, msg, len, flags, to, tolen);
522 if (r == -1 && errno == EWOULDBLOCK)
524 block (s, REACTOR_WRITE);
532 pth_sendmsg (int s, const struct msghdr *msg, unsigned int flags)
537 r = sendmsg (s, msg, flags);
538 if (r == -1 && errno == EWOULDBLOCK)
540 block (s, REACTOR_WRITE);
548 pth_recv (int s, void *buf, int len, unsigned int flags)
553 r = recv (s, buf, len, flags);
554 if (r == -1 && errno == EWOULDBLOCK)
556 block (s, REACTOR_READ);
564 pth_recvfrom (int s, void *buf, int len, unsigned int flags,
565 struct sockaddr *from, int *fromlen)
570 r = recvfrom (s, buf, len, flags, from, fromlen);
571 if (r == -1 && errno == EWOULDBLOCK)
573 block (s, REACTOR_READ);
581 pth_recvmsg (int s, struct msghdr *msg, unsigned int flags)
586 r = recvmsg (s, msg, flags);
587 if (r == -1 && errno == EWOULDBLOCK)
589 block (s, REACTOR_READ);
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.
603 pth_poll (struct pollfd *fds, unsigned int n, int timeout)
608 r = poll (fds, n, 0);
611 _poll (fds, n, timeout);
612 if (current_pth->poll_timeout) return 0;
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.
623 pth_select (int n, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
624 struct timeval *timeout)
626 pool p = new_subpool (current_pth->pool);
627 vector v = new_vector (p, struct pollfd);
629 struct pollfd pfd, *fds;
631 /* Convert the sets into an array of poll descriptors. */
632 for (i = 0; i < n; ++i)
634 if (readfds && FD_ISSET (i, readfds))
639 vector_push_back (v, pfd);
641 if (writefds && FD_ISSET (i, writefds))
644 pfd.events = POLLOUT;
646 vector_push_back (v, pfd);
648 if (exceptfds && FD_ISSET (i, exceptfds))
651 pfd.events = POLLERR;
653 vector_push_back (v, pfd);
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);
662 r = pth_poll (fds, n, to);
671 if (readfds) FD_ZERO (readfds);
672 if (writefds) FD_ZERO (writefds);
673 if (exceptfds) FD_ZERO (exceptfds);
682 /* Convert the returned events into sets. */
683 for (i = 0; i < n; ++i)
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);
698 pth_wait_readable (int fd)
701 struct pollfd fds[1];
704 fds[0].events = POLLIN;
705 fds[0].revents = 0; /* Don't care. */
708 r = poll (fds, 1, -1);
711 block (fd, REACTOR_READ);
715 return r >= 0 ? 1 : -1;
719 pth_wait_writable (int fd)
722 struct pollfd fds[1];
725 fds[0].events = POLLOUT;
726 fds[0].revents = 0; /* Don't care. */
729 r = poll (fds, 1, -1);
732 block (fd, REACTOR_WRITE);
736 return r >= 0 ? 1 : -1;
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. */
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
750 static struct putenv_map {
751 struct putenv_map *next;
757 do_setenv (const char *name, const char *value)
759 struct putenv_map *m;
761 for (m = putenv_map; m; m = m->next)
762 if (strcmp (m->name, name) == 0)
764 /* Modify the env in-place. */
766 snprintf (m->env, sizeof m->env, "%s=%s", name, value);
771 /* Create a new entry. */
772 m = pmalloc (global_pool, sizeof *m);
773 m->next = putenv_map;
778 #define do_unsetenv(name) putenv ((name))
781 #error "no setenv/unsetenv or putenv in your libc"
787 if (current_pth->lang == 0)
788 do_unsetenv ("LANGUAGE");
790 do_setenv ("LANGUAGE", current_pth->lang);
794 /* Please see gettext info file, node ``Being a `gettext' grok'', section
795 * ``Changing the language at runtime''.
797 extern int _nl_msg_cat_cntr;
806 if (current_pth->tz == 0)
809 do_setenv ("TZ", current_pth->tz);
813 pth_set_language (const char *lang)
815 current_pth->lang = pstrdup (current_pth->pool, lang);
820 pth_set_tz (const char *tz)
822 current_pth->tz = pstrdup (current_pth->pool, tz);
827 _pth_switch_thread_to_calling_context ()
829 mctx_switch (¤t_pth->thread_ctx, ¤t_pth->calling_ctx);
833 _pth_switch_calling_to_thread_context (pseudothread pth)
835 current_pth = pth; /* Set current thread. */
836 mctx_switch (¤t_pth->calling_ctx, ¤t_pth->thread_ctx);
840 _pth_alarm_received ()
842 return current_pth->alarm_received;
846 block (int sock, int operations)
848 /* Register a read event in the reactor. */
849 reactor_handle handle
850 = reactor_register (sock, operations, return_from_block, current_pth);
852 /* Swap context back to the calling context. */
853 _pth_switch_thread_to_calling_context ();
855 /* Unregister the handle. */
856 reactor_unregister (handle);
858 /* Received alarm signal? - Exit. */
859 if (_pth_alarm_received ())
862 /* Restore environment. */
868 return_from_block (int sock, int events, void *vpth)
870 /* Swap back to the thread context. */
871 _pth_switch_calling_to_thread_context ((pseudothread) vpth);
877 /* Register a timer in the reactor. */
879 = reactor_set_timer (current_pth->pool, timeout,
880 return_from_sleep, current_pth);
882 /* Swap context back to the calling context. */
883 _pth_switch_thread_to_calling_context ();
885 /* Received alarm signal? - Exit. */
886 if (_pth_alarm_received ())
888 reactor_unset_timer_early (timer);
892 /* Note: no need to unregister the timer, since it has fired. */
894 /* Restore environment. */
900 return_from_sleep (void *vpth)
902 /* Swap back to the thread context. */
903 _pth_switch_calling_to_thread_context ((pseudothread) vpth);
907 _poll (struct pollfd *fds, unsigned int n, int timeout)
909 reactor_timer timer = 0;
910 reactor_handle handle[n];
913 (void) &timer; /* Tell gcc not to put it in a register. */
914 current_pth->poll_timeout = 0;
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);
924 timer = reactor_set_timer (current_pth->pool, timeout,
925 return_from_poll_timeout, current_pth);
927 /* Swap context back to calling context. */
928 _pth_switch_thread_to_calling_context ();
930 /* Unregister all the handles. */
931 for (i = 0; i < n; ++i)
932 reactor_unregister (handle[i]);
934 /* Delete the timer, if it exists but hasn't fired. */
935 if (timer && !current_pth->poll_timeout)
936 reactor_unset_timer_early (timer);
938 /* Received alarm signal? Exit. */
939 if (_pth_alarm_received ())
942 /* Restore environment. */
948 return_from_poll (int sock, int events, void *vpth)
950 /* Swap back to the thread context. */
951 _pth_switch_calling_to_thread_context ((pseudothread) vpth);
955 return_from_poll_timeout (void *vpth)
957 pseudothread pth = (pseudothread) vpth;
959 pth->poll_timeout = 1;
961 /* Swap back to the thread context. */
962 _pth_switch_calling_to_thread_context (pth);
966 return_from_alarm (void *vpth)
968 pseudothread pth = (pseudothread) vpth;
970 pth->alarm_received = 1;
971 pth->alarm_timer = 0;
973 /* Swap back to the thread context. */
974 _pth_switch_calling_to_thread_context (pth);
978 pseudothread_get_threads (pool pool)
980 vector v = new_vector (pool, struct pseudothread);
983 for (i = 0; i < vector_size (threads); ++i)
986 struct pseudothread pth_copy;
988 vector_get (threads, i, pth);
992 /* Perform a deep copy of the structure. */
993 memcpy (&pth_copy, pth, sizeof pth_copy);
995 pth_copy.name = pstrdup (pool, pth_copy.name);
997 pth_copy.lang = pstrdup (pool, pth_copy.lang);
999 pth_copy.tz = pstrdup (pool, pth_copy.tz);
1001 vector_push_back (v, pth_copy);
1009 pseudothread_count_threads (void)
1014 for (i = 0; i < vector_size (threads); ++i)
1018 vector_get (threads, i, pth);