head 1.7; access; symbols PTH_2_0_7:1.6 PTH_2_0_6:1.5 PTH_2_0_5:1.5 PTH_2_0_4:1.5 PTH_2_0_3:1.4 PTH_2_0_2:1.3 PTH_2_0_1:1.3 PTH_2_0_0:1.2 PTH_2_0b2:1.1 PTH_2_0b1:1.1 PTH_2_0b0:1.1; locks; strict; comment @ * @; 1.7 date 2007.01.01.18.23.53; author rse; state Exp; branches; next 1.6; commitid 9DhdiirNzQPBIP0s; 1.6 date 2006.06.08.17.54.53; author rse; state Exp; branches; next 1.5; commitid x8N3mLVdQgkbdeAr; 1.5 date 2004.12.31.19.34.45; author rse; state Exp; branches; next 1.4; 1.4 date 2004.12.03.16.21.08; author rse; state Exp; branches; next 1.3; 1.3 date 2004.07.13.10.50.49; author rse; state Exp; branches; next 1.2; 1.2 date 2003.01.01.15.49.12; author rse; state Exp; branches; next 1.1; 1.1 date 2002.11.03.09.59.33; author rse; state Exp; branches; next ; desc @@ 1.7 log @Adjusted all copyright messages for new year 2007. @ text @/* ** GNU Pth - The GNU Portable Threads ** Copyright (c) 1999-2007 Ralf S. Engelschall ** ** This file is part of GNU Pth, a non-preemptive thread scheduling ** library which can be found at http://www.gnu.org/software/pth/. ** ** This library is free software; you can redistribute it and/or ** modify it under the terms of the GNU Lesser General Public ** License as published by the Free Software Foundation; either ** version 2.1 of the License, or (at your option) any later version. ** ** This library is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ** Lesser General Public License for more details. ** ** You should have received a copy of the GNU Lesser General Public ** License along with this library; if not, write to the Free Software ** Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 ** USA, or contact Ralf S. Engelschall . ** ** pth_uctx.c: Pth user-space context handling (stand-alone sub-API) */ /* ``It worries me however, to realize how tough an ass-hole I have had to be, in order to get to stick to the principle of doing things right, rather than "just hack it in".'' -- Poul-Henning Kamp */ #include "pth_p.h" /* user-space context structure */ struct pth_uctx_st { int uc_stack_own; /* whether stack were allocated by us */ char *uc_stack_ptr; /* pointer to start address of stack area */ size_t uc_stack_len; /* size of stack area */ int uc_mctx_set; /* whether uc_mctx is set */ pth_mctx_t uc_mctx; /* saved underlying machine context */ }; /* create user-space context structure */ int pth_uctx_create( pth_uctx_t *puctx) { pth_uctx_t uctx; /* argument sanity checking */ if (puctx == NULL) return pth_error(FALSE, EINVAL); /* allocate the context structure */ if ((uctx = (pth_uctx_t)malloc(sizeof(struct pth_uctx_st))) == NULL) return pth_error(FALSE, errno); /* initialize the context structure */ uctx->uc_stack_own = FALSE; uctx->uc_stack_ptr = NULL; uctx->uc_stack_len = 0; uctx->uc_mctx_set = FALSE; memset((void *)&uctx->uc_mctx, 0, sizeof(pth_mctx_t)); /* pass result to caller */ *puctx = uctx; return TRUE; } /* trampoline context */ typedef struct { pth_mctx_t *mctx_parent; pth_uctx_t uctx_this; pth_uctx_t uctx_after; void (*start_func)(void *); void *start_arg; } pth_uctx_trampoline_t; pth_uctx_trampoline_t pth_uctx_trampoline_ctx; /* trampoline function for pth_uctx_make() */ static void pth_uctx_trampoline(void) { volatile pth_uctx_trampoline_t ctx; /* move context information from global to local storage */ ctx.mctx_parent = pth_uctx_trampoline_ctx.mctx_parent; ctx.uctx_this = pth_uctx_trampoline_ctx.uctx_this; ctx.uctx_after = pth_uctx_trampoline_ctx.uctx_after; ctx.start_func = pth_uctx_trampoline_ctx.start_func; ctx.start_arg = pth_uctx_trampoline_ctx.start_arg; /* switch back to parent */ pth_mctx_switch(&(ctx.uctx_this->uc_mctx), ctx.mctx_parent); /* enter start function */ (*ctx.start_func)(ctx.start_arg); /* switch to successor user-space context */ if (ctx.uctx_after != NULL) pth_mctx_restore(&(ctx.uctx_after->uc_mctx)); /* terminate process (the only reasonable thing to do here) */ exit(0); /* NOTREACHED */ return; } /* make setup of user-space context structure */ int pth_uctx_make( pth_uctx_t uctx, char *sk_addr, size_t sk_size, const sigset_t *sigmask, void (*start_func)(void *), void *start_arg, pth_uctx_t uctx_after) { pth_mctx_t mctx_parent; sigset_t ss; /* argument sanity checking */ if (uctx == NULL || start_func == NULL || sk_size < 16*1024) return pth_error(FALSE, EINVAL); /* configure run-time stack */ if (sk_addr == NULL) { if ((sk_addr = (char *)malloc(sk_size)) == NULL) return pth_error(FALSE, errno); uctx->uc_stack_own = TRUE; } else uctx->uc_stack_own = FALSE; uctx->uc_stack_ptr = sk_addr; uctx->uc_stack_len = sk_size; /* configure the underlying machine context */ if (!pth_mctx_set(&uctx->uc_mctx, pth_uctx_trampoline, uctx->uc_stack_ptr, uctx->uc_stack_ptr+uctx->uc_stack_len)) return pth_error(FALSE, errno); /* move context information into global storage for the trampoline jump */ pth_uctx_trampoline_ctx.mctx_parent = &mctx_parent; pth_uctx_trampoline_ctx.uctx_this = uctx; pth_uctx_trampoline_ctx.uctx_after = uctx_after; pth_uctx_trampoline_ctx.start_func = start_func; pth_uctx_trampoline_ctx.start_arg = start_arg; /* optionally establish temporary signal mask */ if (sigmask != NULL) sigprocmask(SIG_SETMASK, sigmask, &ss); /* perform the trampoline step */ pth_mctx_switch(&mctx_parent, &(uctx->uc_mctx)); /* optionally restore original signal mask */ if (sigmask != NULL) sigprocmask(SIG_SETMASK, &ss, NULL); /* finally flag that the context is now configured */ uctx->uc_mctx_set = TRUE; return TRUE; } /* switch from current to other user-space context */ int pth_uctx_switch( pth_uctx_t uctx_from, pth_uctx_t uctx_to) { /* argument sanity checking */ if (uctx_from == NULL || uctx_to == NULL) return pth_error(FALSE, EINVAL); if (!(uctx_to->uc_mctx_set)) return pth_error(FALSE, EPERM); /* switch underlying machine context */ uctx_from->uc_mctx_set = TRUE; pth_mctx_switch(&(uctx_from->uc_mctx), &(uctx_to->uc_mctx)); return TRUE; } /* destroy user-space context structure */ int pth_uctx_destroy( pth_uctx_t uctx) { /* argument sanity checking */ if (uctx == NULL) return pth_error(FALSE, EINVAL); /* deallocate dynamically allocated stack */ if (uctx->uc_stack_own && uctx->uc_stack_ptr != NULL) free(uctx->uc_stack_ptr); /* deallocate context structure */ free(uctx); return TRUE; } @ 1.6 log @Adjusted all copyright messages for new year 2006 @ text @d3 1 a3 1 ** Copyright (c) 1999-2006 Ralf S. Engelschall @ 1.5 log @Adjusted all copyright messages for new year 2005. @ text @d3 1 a3 1 ** Copyright (c) 1999-2005 Ralf S. Engelschall @ 1.4 log @The pth_uctx_save() and pth_uctx_restore() API functions unfortunately were broken by design because they are C _functions_. This leads to one more deadly nesting on the run-time stack which effectively caused the pth_mctx_restore() in pth_uctx_restore() to return to the end of pth_uctx_save() but then the control flow unfortunately returns to the pth_uctx_restore() caller instead of the pth_uctx_save() caller because the call to pth_uctx_restore() had already overwritten the run-time stack position where the original return address for the pth_uctx_save() call was stored. The only workaround would be to #define pth_uctx_save() and pth_uctx_restore() as C _macros_, but this then would require that lots of the GNU Pth internals from pth_mctx.c would have to be exported in the GNU Pth API (which in turn is not acceptable). So, the only consequence is to remove the two functions again from the GNU Pth API. Prompted by hints from: Stefan Brantschen @ text @d3 1 a3 1 ** Copyright (c) 1999-2004 Ralf S. Engelschall @ 1.3 log @Adjusted all copyright messages for new year 2004. @ text @d100 1 a100 1 pth_uctx_restore(ctx.uctx_after); d153 1 a153 1 pth_mctx_switch(&mctx_parent, &uctx->uc_mctx); a164 33 /* save current user-space context */ int pth_uctx_save( pth_uctx_t uctx) { /* argument sanity checking */ if (uctx == NULL) return pth_error(FALSE, EINVAL); /* save underlying machine context */ pth_mctx_save(&uctx->uc_mctx); uctx->uc_mctx_set = TRUE; return TRUE; } /* restore current user-space context */ int pth_uctx_restore( pth_uctx_t uctx) { /* argument sanity checking */ if (uctx == NULL) return pth_error(FALSE, EINVAL); if (!(uctx->uc_mctx_set)) return pth_error(FALSE, EPERM); /* restore underlying machine context */ pth_mctx_restore(&uctx->uc_mctx); return TRUE; } d179 1 a179 1 pth_mctx_switch(&uctx_from->uc_mctx, &uctx_to->uc_mctx); @ 1.2 log @Adjusted all copyright messages for new year 2003. @ text @d3 1 a3 1 ** Copyright (c) 1999-2003 Ralf S. Engelschall @ 1.1 log @Added a stand-alone sub-API for manual user-space context switching. It is somewhat modeled after the POSIX ucontext(3) facility and consists of an opaque data type pth_uctx_t and the management functions pth_uctx_create(), pth_uctx_make(), pth_uctx_save(), pth_uctx_restore(), pth_uctx_switch() and pth_uctx_destroy(). These functions are based on the same underlying machine context switching facility (pth_mctx) the threads in GNU Pth are using. This facility can be used to implement co-routines without a full real multithreading environment or even to implement an own multithreading environment. @ text @d3 1 a3 1 ** Copyright (c) 1999-2002 Ralf S. Engelschall @