head 1.96; access; symbols PTH_2_0_7:1.94 PTH_2_0_6:1.93 PTH_2_0_5:1.93 PTH_2_0_4:1.93 PTH_2_0_3:1.92 PTH_2_0_2:1.91 PTH_2_0_1:1.91 PTH_2_0_0:1.89 PTH_2_0b2:1.88 PTH_2_0b1:1.86 PTH_2_0b0:1.85 PTH_1_4:1.81.0.2 PTH_1_4_1:1.81 PTH_1_4_0:1.80 PTH_1_3_7:1.77 PTH_1_4a3:1.78 PTH_1_3_6:1.77 PTH_1_4a2:1.78 PTH_1_3_5:1.77 PTH_1_4a1:1.78 PTH_1_3_4:1.77 PTH_1_3:1.77.0.2 PTH_1_3_3:1.77 PTH_1_3_2:1.76 PTH_1_3_1:1.75 PTH_1_3_0:1.75 PTH_1_3b3:1.73 PTH_1_2_3:1.64.2.1 PTH_1_3b2:1.71 PTH_1_3b1:1.70 PTH_1_3a5:1.67 PTH_1_3a4:1.67 PTH_1_3a3:1.67 PTH_1_2_2:1.64.2.1 PTH_1_3a2:1.67 PTH_1_2_1:1.64.2.1 PTH_1_3a1:1.65 PTH_1_2:1.64.0.2 PTH_1_2_0:1.64 PTH_1_2b8:1.63 PTH_1_2b7:1.63 PTH_1_1_6:1.59 PTH_1_2b6:1.61 PTH_1_2b5:1.61 PTH_1_2b4:1.61 PTH_1_2b3:1.61 PTH_1_2b2:1.60 PTH_1_2b1:1.60 PTH_1_1_5:1.59 PTH_1_0_6:1.50 PTH_1_0_5:1.50 PTH_1_0:1.50.0.2 PTH_1_1:1.59.0.2 PTH_1_1_4:1.59 PTH_1_1_3:1.55 PTH_1_1_2:1.55 PTH_1_1_1:1.55 PTH_1_1_0:1.55 PTH_1_1b7:1.54 PTH_1_1b6:1.54 PTH_1_1b5:1.54 PTH_1_1b4:1.54 PTH_1_1b3:1.52 PTH_1_1b2:1.52 PTH_1_1b1:1.51 PTH_1_0_4:1.50 PTH_1_0_3:1.50 PTH_1_0_2:1.50 PTH_1_0_1:1.50 PTH_1_0_0:1.50 PTH_1_0b8:1.50 PTH_1_0b7:1.46 PTH_1_0b6:1.46 PTH_1_0b5:1.46 PTH_1_0b4:1.41 PTH_1_0b3:1.39 PTH_1_0b2:1.39 PTH_1_0b1:1.37 PTH_0_9_21:1.34 PTH_0_9_20:1.34 PTH_0_9_19:1.34 PTH_0_9_18:1.32 PTH_0_9_17:1.30 PTH_0_9_16:1.29 PTH_0_9_15:1.28 PTH_0_9_14:1.23 PTH_0_9_13:1.21 PTH_0_9_12:1.20 PTH_0_9_11:1.18 PTH_0_9_10:1.18 PTH_0_9_9:1.17 PTH_0_9_8:1.17 PTH_0_9_7:1.12 PTH_0_9_6:1.9 PTH_0_9_5:1.7 PTH_0_9_4:1.7 PTH_0_9_3:1.6 PTH_0_9_2:1.3 PTH_0_9_1:1.1.1.1 PTH_0_9_0:1.1.1.1 RSE:1.1.1; locks; strict; comment @ * @; 1.96 date 2007.01.01.18.23.53; author rse; state Exp; branches; next 1.95; commitid 9DhdiirNzQPBIP0s; 1.95 date 2006.11.27.08.14.11; author rse; state Exp; branches; next 1.94; commitid db0TM7qhelAethWr; 1.94 date 2006.06.08.17.54.53; author rse; state Exp; branches; next 1.93; commitid x8N3mLVdQgkbdeAr; 1.93 date 2004.12.31.19.34.45; author rse; state Exp; branches; next 1.92; 1.92 date 2004.10.08.16.17.02; author rse; state Exp; branches; next 1.91; 1.91 date 2004.07.13.10.50.49; author rse; state Exp; branches; next 1.90; 1.90 date 2003.03.22.20.31.49; author rse; state Exp; branches; next 1.89; 1.89 date 2003.01.01.15.49.12; author rse; state Exp; branches; next 1.88; 1.88 date 2002.11.09.16.29.26; author rse; state Exp; branches; next 1.87; 1.87 date 2002.11.09.16.07.52; author rse; state Exp; branches; next 1.86; 1.86 date 2002.11.08.16.17.47; author rse; state Exp; branches; next 1.85; 1.85 date 2002.11.07.15.38.40; author rse; state Exp; branches; next 1.84; 1.84 date 2002.11.05.19.43.06; author rse; state Exp; branches; next 1.83; 1.83 date 2002.11.05.19.39.09; author rse; state Exp; branches; next 1.82; 1.82 date 2002.11.03.11.15.05; author rse; state Exp; branches; next 1.81; 1.81 date 2002.01.27.11.03.41; author rse; state Exp; branches; next 1.80; 1.80 date 2001.03.24.14.51.04; author rse; state Exp; branches; next 1.79; 1.79 date 2001.02.25.17.08.07; author rse; state Exp; branches; next 1.78; 1.78 date 2000.03.12.16.43.16; author rse; state Exp; branches; next 1.77; 1.77 date 2000.03.10.09.25.08; author rse; state Exp; branches 1.77.2.1; next 1.76; 1.76 date 2000.02.24.12.35.01; author rse; state Exp; branches; next 1.75; 1.75 date 2000.02.19.16.08.11; author rse; state Exp; branches; next 1.74; 1.74 date 2000.02.19.16.06.02; author rse; state Exp; branches; next 1.73; 1.73 date 2000.02.13.17.24.02; author rse; state Exp; branches; next 1.72; 1.72 date 2000.02.13.16.03.47; author rse; state Exp; branches; next 1.71; 1.71 date 2000.01.26.13.06.38; author rse; state Exp; branches; next 1.70; 1.70 date 2000.01.26.10.06.37; author rse; state Exp; branches; next 1.69; 1.69 date 2000.01.26.10.02.26; author rse; state Exp; branches; next 1.68; 1.68 date 2000.01.24.15.52.31; author rse; state Exp; branches; next 1.67; 1.67 date 99.12.30.21.59.00; author rse; state Exp; branches; next 1.66; 1.66 date 99.11.09.08.11.32; author rse; state Exp; branches; next 1.65; 1.65 date 99.11.01.10.27.19; author rse; state Exp; branches; next 1.64; 1.64 date 99.10.31.11.46.13; author rse; state Exp; branches 1.64.2.1; next 1.63; 1.63 date 99.10.19.14.40.25; author rse; state Exp; branches; next 1.62; 1.62 date 99.10.19.12.18.26; author rse; state Exp; branches; next 1.61; 1.61 date 99.09.17.08.01.55; author rse; state Exp; branches; next 1.60; 1.60 date 99.09.01.08.51.24; author rse; state Exp; branches; next 1.59; 1.59 date 99.08.30.17.17.17; author rse; state Exp; branches; next 1.58; 1.58 date 99.08.30.13.41.44; author rse; state Exp; branches; next 1.57; 1.57 date 99.08.29.11.35.54; author rse; state Exp; branches; next 1.56; 1.56 date 99.08.28.14.37.48; author rse; state Exp; branches; next 1.55; 1.55 date 99.08.19.15.08.53; author rse; state Exp; branches; next 1.54; 1.54 date 99.08.13.14.52.03; author rse; state Exp; branches; next 1.53; 1.53 date 99.08.13.09.10.42; author rse; state Exp; branches; next 1.52; 1.52 date 99.08.09.14.34.33; author rse; state Exp; branches; next 1.51; 1.51 date 99.08.03.12.24.03; author rse; state Exp; branches; next 1.50; 1.50 date 99.07.16.07.59.27; author rse; state Exp; branches; next 1.49; 1.49 date 99.07.16.07.16.59; author rse; state Exp; branches; next 1.48; 1.48 date 99.07.16.07.08.04; author rse; state Exp; branches; next 1.47; 1.47 date 99.07.15.15.51.05; author rse; state Exp; branches; next 1.46; 1.46 date 99.07.11.15.09.25; author rse; state Exp; branches; next 1.45; 1.45 date 99.07.11.11.58.38; author rse; state Exp; branches; next 1.44; 1.44 date 99.07.10.15.14.47; author rse; state Exp; branches; next 1.43; 1.43 date 99.07.10.14.21.17; author rse; state Exp; branches; next 1.42; 1.42 date 99.07.09.08.06.41; author rse; state Exp; branches; next 1.41; 1.41 date 99.07.08.10.34.01; author rse; state Exp; branches; next 1.40; 1.40 date 99.07.08.10.19.11; author rse; state Exp; branches; next 1.39; 1.39 date 99.07.04.13.59.00; author rse; state Exp; branches; next 1.38; 1.38 date 99.07.04.12.05.35; author rse; state Exp; branches; next 1.37; 1.37 date 99.06.28.09.45.24; author rse; state Exp; branches; next 1.36; 1.36 date 99.06.27.15.40.30; author rse; state Exp; branches; next 1.35; 1.35 date 99.06.27.15.38.04; author rse; state Exp; branches; next 1.34; 1.34 date 99.06.21.14.24.47; author rse; state Exp; branches; next 1.33; 1.33 date 99.06.21.09.42.57; author rse; state Exp; branches; next 1.32; 1.32 date 99.06.20.09.58.57; author rse; state Exp; branches; next 1.31; 1.31 date 99.06.19.15.54.35; author rse; state Exp; branches; next 1.30; 1.30 date 99.06.18.09.25.40; author rse; state Exp; branches; next 1.29; 1.29 date 99.06.04.21.26.10; author rse; state Exp; branches; next 1.28; 1.28 date 99.06.04.10.58.39; author rse; state Exp; branches; next 1.27; 1.27 date 99.06.04.10.47.42; author rse; state Exp; branches; next 1.26; 1.26 date 99.06.03.18.45.04; author rse; state Exp; branches; next 1.25; 1.25 date 99.06.02.14.14.48; author rse; state Exp; branches; next 1.24; 1.24 date 99.06.02.14.12.02; author rse; state Exp; branches; next 1.23; 1.23 date 99.06.01.15.29.22; author rse; state Exp; branches; next 1.22; 1.22 date 99.06.01.14.36.33; author rse; state Exp; branches; next 1.21; 1.21 date 99.06.01.09.55.26; author rse; state Exp; branches; next 1.20; 1.20 date 99.05.30.13.08.37; author rse; state Exp; branches; next 1.19; 1.19 date 99.05.30.09.52.10; author rse; state Exp; branches; next 1.18; 1.18 date 99.05.28.09.05.12; author rse; state Exp; branches; next 1.17; 1.17 date 99.05.24.11.45.15; author rse; state Exp; branches; next 1.16; 1.16 date 99.05.24.10.24.25; author rse; state Exp; branches; next 1.15; 1.15 date 99.05.24.10.07.44; author rse; state Exp; branches; next 1.14; 1.14 date 99.05.24.07.58.13; author rse; state Exp; branches; next 1.13; 1.13 date 99.05.24.07.45.56; author rse; state Exp; branches; next 1.12; 1.12 date 99.05.23.14.11.53; author rse; state Exp; branches; next 1.11; 1.11 date 99.05.23.14.08.41; author rse; state Exp; branches; next 1.10; 1.10 date 99.05.23.12.37.55; author rse; state Exp; branches; next 1.9; 1.9 date 99.05.22.14.37.53; author rse; state Exp; branches; next 1.8; 1.8 date 99.05.22.12.28.30; author rse; state Exp; branches; next 1.7; 1.7 date 99.05.21.09.44.10; author rse; state Exp; branches; next 1.6; 1.6 date 99.05.14.20.39.24; author rse; state Exp; branches; next 1.5; 1.5 date 99.05.14.20.32.03; author rse; state Exp; branches; next 1.4; 1.4 date 99.05.14.20.19.24; author rse; state Exp; branches; next 1.3; 1.3 date 99.05.14.13.43.31; author rse; state Exp; branches; next 1.2; 1.2 date 99.05.14.09.40.05; author rse; state Exp; branches; next 1.1; 1.1 date 99.05.13.12.18.16; author rse; state Exp; branches 1.1.1.1; next ; 1.77.2.1 date 2001.02.25.17.17.49; author rse; state Exp; branches; next ; 1.64.2.1 date 99.11.01.10.25.01; author rse; state Exp; branches; next ; 1.1.1.1 date 99.05.13.12.18.16; author rse; state Exp; branches; next ; desc @@ 1.96 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_sched.c: Pth thread scheduler, the real heart of Pth */ /* ``Recursive, adj.; see Recursive.'' -- Unknown */ #include "pth_p.h" intern pth_t pth_main; /* the main thread */ intern pth_t pth_sched; /* the permanent scheduler thread */ intern pth_t pth_current; /* the currently running thread */ intern pth_pqueue_t pth_NQ; /* queue of new threads */ intern pth_pqueue_t pth_RQ; /* queue of threads ready to run */ intern pth_pqueue_t pth_WQ; /* queue of threads waiting for an event */ intern pth_pqueue_t pth_SQ; /* queue of suspended threads */ intern pth_pqueue_t pth_DQ; /* queue of terminated threads */ intern int pth_favournew; /* favour new threads on startup */ intern float pth_loadval; /* average scheduler load value */ static int pth_sigpipe[2]; /* internal signal occurrence pipe */ static sigset_t pth_sigpending; /* mask of pending signals */ static sigset_t pth_sigblock; /* mask of signals we block in scheduler */ static sigset_t pth_sigcatch; /* mask of signals we have to catch */ static sigset_t pth_sigraised; /* mask of raised signals */ static pth_time_t pth_loadticknext; static pth_time_t pth_loadtickgap = PTH_TIME(1,0); /* initialize the scheduler ingredients */ intern int pth_scheduler_init(void) { /* create the internal signal pipe */ if (pipe(pth_sigpipe) == -1) return pth_error(FALSE, errno); if (pth_fdmode(pth_sigpipe[0], PTH_FDMODE_NONBLOCK) == PTH_FDMODE_ERROR) return pth_error(FALSE, errno); if (pth_fdmode(pth_sigpipe[1], PTH_FDMODE_NONBLOCK) == PTH_FDMODE_ERROR) return pth_error(FALSE, errno); /* initialize the essential threads */ pth_sched = NULL; pth_current = NULL; /* initalize the thread queues */ pth_pqueue_init(&pth_NQ); pth_pqueue_init(&pth_RQ); pth_pqueue_init(&pth_WQ); pth_pqueue_init(&pth_SQ); pth_pqueue_init(&pth_DQ); /* initialize scheduling hints */ pth_favournew = 1; /* the default is the original behaviour */ /* initialize load support */ pth_loadval = 1.0; pth_time_set(&pth_loadticknext, PTH_TIME_NOW); return TRUE; } /* drop all threads (except for the currently active one) */ intern void pth_scheduler_drop(void) { pth_t t; /* clear the new queue */ while ((t = pth_pqueue_delmax(&pth_NQ)) != NULL) pth_tcb_free(t); pth_pqueue_init(&pth_NQ); /* clear the ready queue */ while ((t = pth_pqueue_delmax(&pth_RQ)) != NULL) pth_tcb_free(t); pth_pqueue_init(&pth_RQ); /* clear the waiting queue */ while ((t = pth_pqueue_delmax(&pth_WQ)) != NULL) pth_tcb_free(t); pth_pqueue_init(&pth_WQ); /* clear the suspend queue */ while ((t = pth_pqueue_delmax(&pth_SQ)) != NULL) pth_tcb_free(t); pth_pqueue_init(&pth_SQ); /* clear the dead queue */ while ((t = pth_pqueue_delmax(&pth_DQ)) != NULL) pth_tcb_free(t); pth_pqueue_init(&pth_DQ); return; } /* kill the scheduler ingredients */ intern void pth_scheduler_kill(void) { /* drop all threads */ pth_scheduler_drop(); /* remove the internal signal pipe */ close(pth_sigpipe[0]); close(pth_sigpipe[1]); return; } /* * Update the average scheduler load. * * This is called on every context switch, but we have to adjust the * average load value every second, only. If we're called more than * once per second we handle this by just calculating anything once * and then do NOPs until the next ticks is over. If the scheduler * waited for more than once second (or a thread CPU burst lasted for * more than once second) we simulate the missing calculations. That's * no problem because we can assume that the number of ready threads * then wasn't changed dramatically (or more context switched would have * been occurred and we would have been given more chances to operate). * The actual average load is calculated through an exponential average * formula. */ #define pth_scheduler_load(now) \ if (pth_time_cmp((now), &pth_loadticknext) >= 0) { \ pth_time_t ttmp; \ int numready; \ numready = pth_pqueue_elements(&pth_RQ); \ pth_time_set(&ttmp, (now)); \ do { \ pth_loadval = (numready*0.25) + (pth_loadval*0.75); \ pth_time_sub(&ttmp, &pth_loadtickgap); \ } while (pth_time_cmp(&ttmp, &pth_loadticknext) >= 0); \ pth_time_set(&pth_loadticknext, (now)); \ pth_time_add(&pth_loadticknext, &pth_loadtickgap); \ } /* the heart of this library: the thread scheduler */ intern void *pth_scheduler(void *dummy) { sigset_t sigs; pth_time_t running; pth_time_t snapshot; struct sigaction sa; sigset_t ss; int sig; pth_t t; /* * bootstrapping */ pth_debug1("pth_scheduler: bootstrapping"); /* mark this thread as the special scheduler thread */ pth_sched->state = PTH_STATE_SCHEDULER; /* block all signals in the scheduler thread */ sigfillset(&sigs); pth_sc(sigprocmask)(SIG_SETMASK, &sigs, NULL); /* initialize the snapshot time for bootstrapping the loop */ pth_time_set(&snapshot, PTH_TIME_NOW); /* * endless scheduler loop */ for (;;) { /* * Move threads from new queue to ready queue and optionally * give them maximum priority so they start immediately. */ while ((t = pth_pqueue_tail(&pth_NQ)) != NULL) { pth_pqueue_delete(&pth_NQ, t); t->state = PTH_STATE_READY; if (pth_favournew) pth_pqueue_insert(&pth_RQ, pth_pqueue_favorite_prio(&pth_RQ), t); else pth_pqueue_insert(&pth_RQ, PTH_PRIO_STD, t); pth_debug2("pth_scheduler: new thread \"%s\" moved to top of ready queue", t->name); } /* * Update average scheduler load */ pth_scheduler_load(&snapshot); /* * Find next thread in ready queue */ pth_current = pth_pqueue_delmax(&pth_RQ); if (pth_current == NULL) { fprintf(stderr, "**Pth** SCHEDULER INTERNAL ERROR: " "no more thread(s) available to schedule!?!?\n"); abort(); } pth_debug4("pth_scheduler: thread \"%s\" selected (prio=%d, qprio=%d)", pth_current->name, pth_current->prio, pth_current->q_prio); /* * Raise additionally thread-specific signals * (they are delivered when we switch the context) * * Situation is ('#' = signal pending): * process pending (pth_sigpending): ----#### * thread pending (pth_current->sigpending): --##--## * Result has to be: * process new pending: --###### */ if (pth_current->sigpendcnt > 0) { sigpending(&pth_sigpending); for (sig = 1; sig < PTH_NSIG; sig++) if (sigismember(&pth_current->sigpending, sig)) if (!sigismember(&pth_sigpending, sig)) kill(getpid(), sig); } /* * Set running start time for new thread * and perform a context switch to it */ pth_debug3("pth_scheduler: switching to thread 0x%lx (\"%s\")", (unsigned long)pth_current, pth_current->name); /* update thread times */ pth_time_set(&pth_current->lastran, PTH_TIME_NOW); /* update scheduler times */ pth_time_set(&running, &pth_current->lastran); pth_time_sub(&running, &snapshot); pth_time_add(&pth_sched->running, &running); /* ** ENTERING THREAD ** - by switching the machine context */ pth_current->dispatches++; pth_mctx_switch(&pth_sched->mctx, &pth_current->mctx); /* update scheduler times */ pth_time_set(&snapshot, PTH_TIME_NOW); pth_debug3("pth_scheduler: cameback from thread 0x%lx (\"%s\")", (unsigned long)pth_current, pth_current->name); /* * Calculate and update the time the previous thread was running */ pth_time_set(&running, &snapshot); pth_time_sub(&running, &pth_current->lastran); pth_time_add(&pth_current->running, &running); pth_debug3("pth_scheduler: thread \"%s\" ran %.6f", pth_current->name, pth_time_t2d(&running)); /* * Remove still pending thread-specific signals * (they are re-delivered next time) * * Situation is ('#' = signal pending): * thread old pending (pth_current->sigpending): --##--## * process old pending (pth_sigpending): ----#### * process still pending (sigstillpending): ---#-#-# * Result has to be: * process new pending: -----#-# * thread new pending (pth_current->sigpending): ---#---# */ if (pth_current->sigpendcnt > 0) { sigset_t sigstillpending; sigpending(&sigstillpending); for (sig = 1; sig < PTH_NSIG; sig++) { if (sigismember(&pth_current->sigpending, sig)) { if (!sigismember(&sigstillpending, sig)) { /* thread (and perhaps also process) signal delivered */ sigdelset(&pth_current->sigpending, sig); pth_current->sigpendcnt--; } else if (!sigismember(&pth_sigpending, sig)) { /* thread signal not delivered */ pth_util_sigdelete(sig); } } } } /* * Check for stack overflow */ if (pth_current->stackguard != NULL) { if (*pth_current->stackguard != 0xDEAD) { pth_debug3("pth_scheduler: stack overflow detected for thread 0x%lx (\"%s\")", (unsigned long)pth_current, pth_current->name); /* * if the application doesn't catch SIGSEGVs, we terminate * manually with a SIGSEGV now, but output a reasonable message. */ if (sigaction(SIGSEGV, NULL, &sa) == 0) { if (sa.sa_handler == SIG_DFL) { fprintf(stderr, "**Pth** STACK OVERFLOW: thread pid_t=0x%lx, name=\"%s\"\n", (unsigned long)pth_current, pth_current->name); kill(getpid(), SIGSEGV); sigfillset(&ss); sigdelset(&ss, SIGSEGV); sigsuspend(&ss); abort(); } } /* * else we terminate the thread only and send us a SIGSEGV * which allows the application to handle the situation... */ pth_current->join_arg = (void *)0xDEAD; pth_current->state = PTH_STATE_DEAD; kill(getpid(), SIGSEGV); } } /* * If previous thread is now marked as dead, kick it out */ if (pth_current->state == PTH_STATE_DEAD) { pth_debug2("pth_scheduler: marking thread \"%s\" as dead", pth_current->name); if (!pth_current->joinable) pth_tcb_free(pth_current); else pth_pqueue_insert(&pth_DQ, PTH_PRIO_STD, pth_current); pth_current = NULL; } /* * If thread wants to wait for an event * move it to waiting queue now */ if (pth_current != NULL && pth_current->state == PTH_STATE_WAITING) { pth_debug2("pth_scheduler: moving thread \"%s\" to waiting queue", pth_current->name); pth_pqueue_insert(&pth_WQ, pth_current->prio, pth_current); pth_current = NULL; } /* * migrate old treads in ready queue into higher * priorities to avoid starvation and insert last running * thread back into this queue, too. */ pth_pqueue_increase(&pth_RQ); if (pth_current != NULL) pth_pqueue_insert(&pth_RQ, pth_current->prio, pth_current); /* * Manage the events in the waiting queue, i.e. decide whether their * events occurred and move them to the ready queue. But wait only if * we have already no new or ready threads. */ if ( pth_pqueue_elements(&pth_RQ) == 0 && pth_pqueue_elements(&pth_NQ) == 0) /* still no NEW or READY threads, so we have to wait for new work */ pth_sched_eventmanager(&snapshot, FALSE /* wait */); else /* already NEW or READY threads exists, so just poll for even more work */ pth_sched_eventmanager(&snapshot, TRUE /* poll */); } /* NOTREACHED */ return NULL; } /* * Look whether some events already occurred (or failed) and move * corresponding threads from waiting queue back to ready queue. */ intern void pth_sched_eventmanager(pth_time_t *now, int dopoll) { pth_t nexttimer_thread; pth_event_t nexttimer_ev; pth_time_t nexttimer_value; pth_event_t evh; pth_event_t ev; pth_t t; pth_t tlast; int this_occurred; int any_occurred; fd_set rfds; fd_set wfds; fd_set efds; struct timeval delay; struct timeval *pdelay; sigset_t oss; struct sigaction sa; struct sigaction osa[1+PTH_NSIG]; char minibuf[128]; int loop_repeat; int fdmax; int rc; int sig; int n; pth_debug2("pth_sched_eventmanager: enter in %s mode", dopoll ? "polling" : "waiting"); /* entry point for internal looping in event handling */ loop_entry: loop_repeat = FALSE; /* initialize fd sets */ FD_ZERO(&rfds); FD_ZERO(&wfds); FD_ZERO(&efds); fdmax = -1; /* initialize signal status */ sigpending(&pth_sigpending); sigfillset(&pth_sigblock); sigemptyset(&pth_sigcatch); sigemptyset(&pth_sigraised); /* initialize next timer */ pth_time_set(&nexttimer_value, PTH_TIME_ZERO); nexttimer_thread = NULL; nexttimer_ev = NULL; /* for all threads in the waiting queue... */ any_occurred = FALSE; for (t = pth_pqueue_head(&pth_WQ); t != NULL; t = pth_pqueue_walk(&pth_WQ, t, PTH_WALK_NEXT)) { /* determine signals we block */ for (sig = 1; sig < PTH_NSIG; sig++) if (!sigismember(&(t->mctx.sigs), sig)) sigdelset(&pth_sigblock, sig); /* cancellation support */ if (t->cancelreq == TRUE) any_occurred = TRUE; /* ... and all their events... */ if (t->events == NULL) continue; /* ...check whether events occurred */ ev = evh = t->events; do { if (ev->ev_status == PTH_STATUS_PENDING) { this_occurred = FALSE; /* Filedescriptor I/O */ if (ev->ev_type == PTH_EVENT_FD) { /* filedescriptors are checked later all at once. Here we only assemble them in the fd sets */ if (ev->ev_goal & PTH_UNTIL_FD_READABLE) FD_SET(ev->ev_args.FD.fd, &rfds); if (ev->ev_goal & PTH_UNTIL_FD_WRITEABLE) FD_SET(ev->ev_args.FD.fd, &wfds); if (ev->ev_goal & PTH_UNTIL_FD_EXCEPTION) FD_SET(ev->ev_args.FD.fd, &efds); if (fdmax < ev->ev_args.FD.fd) fdmax = ev->ev_args.FD.fd; } /* Filedescriptor Set Select I/O */ else if (ev->ev_type == PTH_EVENT_SELECT) { /* filedescriptors are checked later all at once. Here we only merge the fd sets. */ pth_util_fds_merge(ev->ev_args.SELECT.nfd, ev->ev_args.SELECT.rfds, &rfds, ev->ev_args.SELECT.wfds, &wfds, ev->ev_args.SELECT.efds, &efds); if (fdmax < ev->ev_args.SELECT.nfd-1) fdmax = ev->ev_args.SELECT.nfd-1; } /* Signal Set */ else if (ev->ev_type == PTH_EVENT_SIGS) { for (sig = 1; sig < PTH_NSIG; sig++) { if (sigismember(ev->ev_args.SIGS.sigs, sig)) { /* thread signal handling */ if (sigismember(&t->sigpending, sig)) { *(ev->ev_args.SIGS.sig) = sig; sigdelset(&t->sigpending, sig); t->sigpendcnt--; this_occurred = TRUE; } /* process signal handling */ if (sigismember(&pth_sigpending, sig)) { if (ev->ev_args.SIGS.sig != NULL) *(ev->ev_args.SIGS.sig) = sig; pth_util_sigdelete(sig); sigdelset(&pth_sigpending, sig); this_occurred = TRUE; } else { sigdelset(&pth_sigblock, sig); sigaddset(&pth_sigcatch, sig); } } } } /* Timer */ else if (ev->ev_type == PTH_EVENT_TIME) { if (pth_time_cmp(&(ev->ev_args.TIME.tv), now) < 0) this_occurred = TRUE; else { /* remember the timer which will be elapsed next */ if ((nexttimer_thread == NULL && nexttimer_ev == NULL) || pth_time_cmp(&(ev->ev_args.TIME.tv), &nexttimer_value) < 0) { nexttimer_thread = t; nexttimer_ev = ev; pth_time_set(&nexttimer_value, &(ev->ev_args.TIME.tv)); } } } /* Message Port Arrivals */ else if (ev->ev_type == PTH_EVENT_MSG) { if (pth_ring_elements(&(ev->ev_args.MSG.mp->mp_queue)) > 0) this_occurred = TRUE; } /* Mutex Release */ else if (ev->ev_type == PTH_EVENT_MUTEX) { if (!(ev->ev_args.MUTEX.mutex->mx_state & PTH_MUTEX_LOCKED)) this_occurred = TRUE; } /* Condition Variable Signal */ else if (ev->ev_type == PTH_EVENT_COND) { if (ev->ev_args.COND.cond->cn_state & PTH_COND_SIGNALED) { if (ev->ev_args.COND.cond->cn_state & PTH_COND_BROADCAST) this_occurred = TRUE; else { if (!(ev->ev_args.COND.cond->cn_state & PTH_COND_HANDLED)) { ev->ev_args.COND.cond->cn_state |= PTH_COND_HANDLED; this_occurred = TRUE; } } } } /* Thread Termination */ else if (ev->ev_type == PTH_EVENT_TID) { if ( ( ev->ev_args.TID.tid == NULL && pth_pqueue_elements(&pth_DQ) > 0) || ( ev->ev_args.TID.tid != NULL && ev->ev_args.TID.tid->state == ev->ev_goal)) this_occurred = TRUE; } /* Custom Event Function */ else if (ev->ev_type == PTH_EVENT_FUNC) { if (ev->ev_args.FUNC.func(ev->ev_args.FUNC.arg)) this_occurred = TRUE; else { pth_time_t tv; pth_time_set(&tv, now); pth_time_add(&tv, &(ev->ev_args.FUNC.tv)); if ((nexttimer_thread == NULL && nexttimer_ev == NULL) || pth_time_cmp(&tv, &nexttimer_value) < 0) { nexttimer_thread = t; nexttimer_ev = ev; pth_time_set(&nexttimer_value, &tv); } } } /* tag event if it has occurred */ if (this_occurred) { pth_debug2("pth_sched_eventmanager: [non-I/O] event occurred for thread \"%s\"", t->name); ev->ev_status = PTH_STATUS_OCCURRED; any_occurred = TRUE; } } } while ((ev = ev->ev_next) != evh); } if (any_occurred) dopoll = TRUE; /* now decide how to poll for fd I/O and timers */ if (dopoll) { /* do a polling with immediate timeout, i.e. check the fd sets only without blocking */ pth_time_set(&delay, PTH_TIME_ZERO); pdelay = &delay; } else if (nexttimer_ev != NULL) { /* do a polling with a timeout set to the next timer, i.e. wait for the fd sets or the next timer */ pth_time_set(&delay, &nexttimer_value); pth_time_sub(&delay, now); pdelay = &delay; } else { /* do a polling without a timeout, i.e. wait for the fd sets only with blocking */ pdelay = NULL; } /* clear pipe and let select() wait for the read-part of the pipe */ while (pth_sc(read)(pth_sigpipe[0], minibuf, sizeof(minibuf)) > 0) ; FD_SET(pth_sigpipe[0], &rfds); if (fdmax < pth_sigpipe[0]) fdmax = pth_sigpipe[0]; /* replace signal actions for signals we've to catch for events */ for (sig = 1; sig < PTH_NSIG; sig++) { if (sigismember(&pth_sigcatch, sig)) { sa.sa_handler = pth_sched_eventmanager_sighandler; sigfillset(&sa.sa_mask); sa.sa_flags = 0; sigaction(sig, &sa, &osa[sig]); } } /* allow some signals to be delivered: Either to our catching handler or directly to the configured handler for signals not catched by events */ pth_sc(sigprocmask)(SIG_SETMASK, &pth_sigblock, &oss); /* now do the polling for filedescriptor I/O and timers WHEN THE SCHEDULER SLEEPS AT ALL, THEN HERE!! */ rc = -1; if (!(dopoll && fdmax == -1)) while ((rc = pth_sc(select)(fdmax+1, &rfds, &wfds, &efds, pdelay)) < 0 && errno == EINTR) ; /* restore signal mask and actions and handle signals */ pth_sc(sigprocmask)(SIG_SETMASK, &oss, NULL); for (sig = 1; sig < PTH_NSIG; sig++) if (sigismember(&pth_sigcatch, sig)) sigaction(sig, &osa[sig], NULL); /* if the timer elapsed, handle it */ if (!dopoll && rc == 0 && nexttimer_ev != NULL) { if (nexttimer_ev->ev_type == PTH_EVENT_FUNC) { /* it was an implicit timer event for a function event, so repeat the event handling for rechecking the function */ loop_repeat = TRUE; } else { /* it was an explicit timer event, standing for its own */ pth_debug2("pth_sched_eventmanager: [timeout] event occurred for thread \"%s\"", nexttimer_thread->name); nexttimer_ev->ev_status = PTH_STATUS_OCCURRED; } } /* if the internal signal pipe was used, adjust the select() results */ if (!dopoll && rc > 0 && FD_ISSET(pth_sigpipe[0], &rfds)) { FD_CLR(pth_sigpipe[0], &rfds); rc--; } /* if an error occurred, avoid confusion in the cleanup loop */ if (rc <= 0) { FD_ZERO(&rfds); FD_ZERO(&wfds); FD_ZERO(&efds); } /* now comes the final cleanup loop where we've to do two jobs: first we've to do the late handling of the fd I/O events and additionally if a thread has one occurred event, we move it from the waiting queue to the ready queue */ /* for all threads in the waiting queue... */ t = pth_pqueue_head(&pth_WQ); while (t != NULL) { /* do the late handling of the fd I/O and signal events in the waiting event ring */ any_occurred = FALSE; if (t->events != NULL) { ev = evh = t->events; do { /* * Late handling for still not occured events */ if (ev->ev_status == PTH_STATUS_PENDING) { /* Filedescriptor I/O */ if (ev->ev_type == PTH_EVENT_FD) { if ( ( ev->ev_goal & PTH_UNTIL_FD_READABLE && FD_ISSET(ev->ev_args.FD.fd, &rfds)) || ( ev->ev_goal & PTH_UNTIL_FD_WRITEABLE && FD_ISSET(ev->ev_args.FD.fd, &wfds)) || ( ev->ev_goal & PTH_UNTIL_FD_EXCEPTION && FD_ISSET(ev->ev_args.FD.fd, &efds)) ) { pth_debug2("pth_sched_eventmanager: " "[I/O] event occurred for thread \"%s\"", t->name); ev->ev_status = PTH_STATUS_OCCURRED; } else if (rc < 0) { /* re-check particular filedescriptor */ int rc2; if (ev->ev_goal & PTH_UNTIL_FD_READABLE) FD_SET(ev->ev_args.FD.fd, &rfds); if (ev->ev_goal & PTH_UNTIL_FD_WRITEABLE) FD_SET(ev->ev_args.FD.fd, &wfds); if (ev->ev_goal & PTH_UNTIL_FD_EXCEPTION) FD_SET(ev->ev_args.FD.fd, &efds); pth_time_set(&delay, PTH_TIME_ZERO); while ((rc2 = pth_sc(select)(ev->ev_args.FD.fd+1, &rfds, &wfds, &efds, &delay)) < 0 && errno == EINTR) ; if (rc2 > 0) { /* cleanup afterwards for next iteration */ FD_CLR(ev->ev_args.FD.fd, &rfds); FD_CLR(ev->ev_args.FD.fd, &wfds); FD_CLR(ev->ev_args.FD.fd, &efds); } else if (rc2 < 0) { /* cleanup afterwards for next iteration */ FD_ZERO(&rfds); FD_ZERO(&wfds); FD_ZERO(&efds); ev->ev_status = PTH_STATUS_FAILED; pth_debug2("pth_sched_eventmanager: " "[I/O] event failed for thread \"%s\"", t->name); } } } /* Filedescriptor Set I/O */ else if (ev->ev_type == PTH_EVENT_SELECT) { if (pth_util_fds_test(ev->ev_args.SELECT.nfd, ev->ev_args.SELECT.rfds, &rfds, ev->ev_args.SELECT.wfds, &wfds, ev->ev_args.SELECT.efds, &efds)) { n = pth_util_fds_select(ev->ev_args.SELECT.nfd, ev->ev_args.SELECT.rfds, &rfds, ev->ev_args.SELECT.wfds, &wfds, ev->ev_args.SELECT.efds, &efds); if (ev->ev_args.SELECT.n != NULL) *(ev->ev_args.SELECT.n) = n; ev->ev_status = PTH_STATUS_OCCURRED; pth_debug2("pth_sched_eventmanager: " "[I/O] event occurred for thread \"%s\"", t->name); } else if (rc < 0) { /* re-check particular filedescriptor set */ int rc2; fd_set *prfds = NULL; fd_set *pwfds = NULL; fd_set *pefds = NULL; fd_set trfds; fd_set twfds; fd_set tefds; if (ev->ev_args.SELECT.rfds) { memcpy(&trfds, ev->ev_args.SELECT.rfds, sizeof(rfds)); prfds = &trfds; } if (ev->ev_args.SELECT.wfds) { memcpy(&twfds, ev->ev_args.SELECT.wfds, sizeof(wfds)); pwfds = &twfds; } if (ev->ev_args.SELECT.efds) { memcpy(&tefds, ev->ev_args.SELECT.efds, sizeof(efds)); pefds = &tefds; } pth_time_set(&delay, PTH_TIME_ZERO); while ((rc2 = pth_sc(select)(ev->ev_args.SELECT.nfd+1, prfds, pwfds, pefds, &delay)) < 0 && errno == EINTR) ; if (rc2 < 0) { ev->ev_status = PTH_STATUS_FAILED; pth_debug2("pth_sched_eventmanager: " "[I/O] event failed for thread \"%s\"", t->name); } } } /* Signal Set */ else if (ev->ev_type == PTH_EVENT_SIGS) { for (sig = 1; sig < PTH_NSIG; sig++) { if (sigismember(ev->ev_args.SIGS.sigs, sig)) { if (sigismember(&pth_sigraised, sig)) { if (ev->ev_args.SIGS.sig != NULL) *(ev->ev_args.SIGS.sig) = sig; pth_debug2("pth_sched_eventmanager: " "[signal] event occurred for thread \"%s\"", t->name); sigdelset(&pth_sigraised, sig); ev->ev_status = PTH_STATUS_OCCURRED; } } } } } /* * post-processing for already occured events */ else { /* Condition Variable Signal */ if (ev->ev_type == PTH_EVENT_COND) { /* clean signal */ if (ev->ev_args.COND.cond->cn_state & PTH_COND_SIGNALED) { ev->ev_args.COND.cond->cn_state &= ~(PTH_COND_SIGNALED); ev->ev_args.COND.cond->cn_state &= ~(PTH_COND_BROADCAST); ev->ev_args.COND.cond->cn_state &= ~(PTH_COND_HANDLED); } } } /* local to global mapping */ if (ev->ev_status != PTH_STATUS_PENDING) any_occurred = TRUE; } while ((ev = ev->ev_next) != evh); } /* cancellation support */ if (t->cancelreq == TRUE) { pth_debug2("pth_sched_eventmanager: cancellation request pending for thread \"%s\"", t->name); any_occurred = TRUE; } /* walk to next thread in waiting queue */ tlast = t; t = pth_pqueue_walk(&pth_WQ, t, PTH_WALK_NEXT); /* * move last thread to ready queue if any events occurred for it. * we insert it with a slightly increased queue priority to give it a * better chance to immediately get scheduled, else the last running * thread might immediately get again the CPU which is usually not * what we want, because we oven use pth_yield() calls to give others * a chance. */ if (any_occurred) { pth_pqueue_delete(&pth_WQ, tlast); tlast->state = PTH_STATE_READY; pth_pqueue_insert(&pth_RQ, tlast->prio+1, tlast); pth_debug2("pth_sched_eventmanager: thread \"%s\" moved from waiting " "to ready queue", tlast->name); } } /* perhaps we have to internally loop... */ if (loop_repeat) { pth_time_set(now, PTH_TIME_NOW); goto loop_entry; } pth_debug1("pth_sched_eventmanager: leaving"); return; } intern void pth_sched_eventmanager_sighandler(int sig) { char c; /* remember raised signal */ sigaddset(&pth_sigraised, sig); /* write signal to signal pipe in order to awake the select() */ c = (int)sig; pth_sc(write)(pth_sigpipe[1], &c, sizeof(char)); return; } @ 1.95 log @fix typo @ text @d3 1 a3 1 ** Copyright (c) 1999-2006 Ralf S. Engelschall @ 1.94 log @Adjusted all copyright messages for new year 2006 @ text @d817 1 a817 1 * we insert it with a slightly increased queue priority to it a @ 1.93 log @Adjusted all copyright messages for new year 2005. @ text @d3 1 a3 1 ** Copyright (c) 1999-2005 Ralf S. Engelschall @ 1.92 log @Added PTH_CTRL_FAVOURNEW control which allows the user to disable the favouring of new threads on scheduling to get more strict priority based scheduling behavior. Triggered by: Vinu V @ text @d3 1 a3 1 ** Copyright (c) 1999-2004 Ralf S. Engelschall @ 1.91 log @Adjusted all copyright messages for new year 2004. @ text @d38 1 d72 3 d186 2 a187 2 * Move threads from new queue to ready queue and give * them maximum priority so they start immediately d192 4 a195 1 pth_pqueue_insert(&pth_RQ, pth_pqueue_favorite_prio(&pth_RQ), t); @ 1.90 log @flush out this trivial pending change in one of my Pth dev queues @ text @d3 1 a3 1 ** Copyright (c) 1999-2003 Ralf S. Engelschall @ 1.89 log @Adjusted all copyright messages for new year 2003. @ text @d361 1 d364 1 @ 1.88 log @Fixed error handling in pth_init(3): it now correctly returns an error instead of abort(3)'ing. @ text @d3 1 a3 1 ** Copyright (c) 1999-2002 Ralf S. Engelschall @ 1.87 log @fix grammar while I'm poking around here ;) @ text @d50 1 a50 1 intern void pth_scheduler_init(void) d53 6 a58 7 if (pipe(pth_sigpipe) == -1) { fprintf(stderr, "**Pth** INIT: Cannot create internal pipe: %s\n", strerror(errno)); abort(); } pth_fdmode(pth_sigpipe[0], PTH_FDMODE_NONBLOCK); pth_fdmode(pth_sigpipe[1], PTH_FDMODE_NONBLOCK); d74 2 a75 1 return; @ 1.86 log @Make sure that in the even manager a polling-only select(2) call uses a correctly initialized timeout parameter. Because SUSv3 says: "Upon successful completion, the select() function may modify the object pointed to by the timeout argument." @ text @d126 1 a126 1 * average load value every second, only. When we're called more than d128 1 a128 1 * and then do NOPs until the next ticks is over. When the scheduler d323 1 a323 1 * When previous thread is now marked as dead, kick it out d335 1 a335 1 * When thread wants to wait for an event @ 1.85 log @Fix dropping of scheduler thread pools and this way fix memory leak. @ text @a657 3 /* pre-configure a raw polling timeout for later checks (see below) */ pth_time_set(&delay, PTH_TIME_ZERO); d693 1 d749 1 @ 1.84 log @fix typo @ text @d84 1 a84 1 while ((t = pth_pqueue_delmax(&pth_NQ)) != NULL); d89 1 a89 1 while ((t = pth_pqueue_delmax(&pth_RQ)) != NULL); d94 1 a94 1 while ((t = pth_pqueue_delmax(&pth_WQ)) != NULL); d99 1 a99 1 while ((t = pth_pqueue_delmax(&pth_SQ)) != NULL); d104 1 a104 1 while ((t = pth_pqueue_delmax(&pth_DQ)) != NULL); @ 1.83 log @1. The function "int pth_event_occurred(pth_event_t)" was replaced with "pth_status_t pth_event_status(pth_event_t)" where pth_status_t can have values of PTH_STATUS_PENDING (replacing the old FALSE return value of pth_event_occurred), PTH_STATUS_OCCURRED (replacing the old TRUE return value of pth_event_occurred), and PTH_STATUS_FAILED (a new return value indicating an error in processing the event). This was scheduler/event-manager errors can be indicated which happended while processing the event. For backward compatibility reasons, a macro pth_event_occurred() was added. This will be removed soon. 2. Use the new PTH_STATUS_FAILED event status in the scheduler's event-manager for filedescriptor events if the internal select(2) call returned with an error. Additionally this PTH_STATUS_FAILED is recognized by the high-level API functions (pth_select, etc) and produce the necessary POSIX conforming return codes (usually -1 and errno == EBADF). Parts submitted by: Thanh Luu @ text @d654 1 a654 1 do two jobs: first we've to the late handling of the fd I/O events and @ 1.82 log @Added thread attribute PTH_ATTR_DISPATCHES which (in bounded attribute objects) is incremented every time the context is switched to the associated thread. This can be used for statistical information. @ text @d371 1 a371 1 * Look whether some events already occurred and move d444 1 a444 1 if (!ev->ev_occurred) { d562 1 a562 1 ev->ev_occurred = TRUE; d636 1 a636 1 nexttimer_ev->ev_occurred = TRUE; d658 3 d674 1 a674 1 if (!ev->ev_occurred) { d685 27 a711 1 ev->ev_occurred = TRUE; d726 1 a726 1 ev->ev_occurred = TRUE; d730 29 d770 1 a770 1 ev->ev_occurred = TRUE; d792 1 a792 1 if (ev->ev_occurred) @ 1.81 log @bump copyright year @ text @d243 1 @ 1.80 log @*** empty log message *** @ text @d3 1 a3 1 ** Copyright (c) 1999-2001 Ralf S. Engelschall @ 1.79 log @*** empty log message *** @ text @d3 1 a3 1 ** Copyright (c) 1999-2000 Ralf S. Engelschall @ 1.78 log @*** empty log message *** @ text @d766 2 a767 1 if (loop_repeat) d769 1 @ 1.77 log @*** empty log message *** @ text @d512 1 a512 1 if (!pth_ring_empty(&(ev->ev_args.MSG.mp->mp_queue))) @ 1.77.2.1 log @*** empty log message *** @ text @d766 1 a766 2 if (loop_repeat) { pth_time_set(now, PTH_TIME_NOW); a767 1 } @ 1.76 log @*** empty log message *** @ text @d185 2 a186 1 while ((t = pth_pqueue_delmax(&pth_NQ)) != NULL) { @ 1.75 log @*** empty log message *** @ text @d180 1 a180 1 while (1) { @ 1.74 log @*** empty log message *** @ text @d364 1 a364 1 /* NOT REACHED */ @ 1.73 log @*** empty log message *** @ text @d363 1 @ 1.72 log @*** empty log message *** @ text @d391 1 d400 4 a538 11 /* Process Termination */ else if (ev->ev_type == PTH_EVENT_PID) { pid_t pid; while ((pid = pth_sc(waitpid)(ev->ev_args.PID.pid, ev->ev_args.PID.status, ev->ev_args.PID.flags|WNOHANG)) < 0 && errno == EINTR) ; if (pid > 0) this_occurred = TRUE; } d541 1 a541 1 if (ev->ev_args.FUNC.func(ev->ev_args.FUNC.func_arg)) d543 11 d624 11 a634 3 pth_debug2("pth_sched_eventmanager: [timeout] event occurred for thread \"%s\"", nexttimer_thread->name); nexttimer_ev->ev_occurred = TRUE; d762 4 @ 1.71 log @*** empty log message *** @ text @d296 2 a297 2 * when the application doesn't catch SIGSEGVs we terminate * manually with a SIGSEGV now but output a reasonable message d354 2 a355 2 * events occurred and move them to the ready queue. But wait only when * we've already no new or ready threads. d551 1 a551 1 /* tag event when it has occurred */ d617 1 a617 1 /* when the timer elapsed then handle it */ d624 1 a624 1 /* when the internal signal pipe was used, adjust the select() results */ d630 1 a630 1 /* when an error occurred, avoid confusion in the cleanup loop */ d639 1 a639 1 additionally when a thread has one occurred event, we move it from the d734 1 a734 1 * move last thread to ready queue when any events occurred for it. @ 1.70 log @*** empty log message *** @ text @d36 1 d69 1 d97 5 @ 1.69 log @*** empty log message *** @ text @d351 2 a352 9 && pth_pqueue_elements(&pth_NQ) == 0) { for (;;) { pth_sched_eventmanager(&snapshot, FALSE /* wait */); if (!( pth_pqueue_elements(&pth_RQ) == 0 && pth_pqueue_elements(&pth_NQ) == 0)) break; pth_time_usleep(10000); } } a374 1 int any_pollings; a410 1 any_pollings = FALSE; a529 1 any_pollings = TRUE; a539 1 any_pollings = TRUE; a553 2 dopoll = TRUE; if (any_pollings) @ 1.68 log @*** empty log message *** @ text @d351 9 a359 2 && pth_pqueue_elements(&pth_NQ) == 0) pth_sched_eventmanager(&snapshot, FALSE /* wait */); d382 1 d419 1 d539 1 d550 1 d565 2 @ 1.67 log @*** empty log message *** @ text @d530 3 a532 3 while ( (pid = pth_sc(waitpid)(ev->ev_args.PID.pid, ev->ev_args.PID.status, ev->ev_args.PID.flags|WNOHANG)) < 0 @ 1.66 log @*** empty log message *** @ text @d3 1 a3 1 ** Copyright (c) 1999 Ralf S. Engelschall @ 1.65 log @*** empty log message *** @ text @d53 1 a53 1 fprintf(stderr, "**Pth** INIT: Cannot create internal pipe: %s\n", d113 1 a113 1 } d115 1 a115 1 /* d155 1 a155 1 /* d170 1 a170 1 /* d223 1 a223 1 pth_debug3("pth_scheduler: switching to thread 0x%lx (\"%s\")", d288 1 a288 1 /* d303 1 a303 1 /* d326 1 a326 1 * When thread wants to wait for an event d330 1 a330 1 pth_debug2("pth_scheduler: moving thread \"%s\" to waiting queue", d389 1 a389 1 pth_debug2("pth_sched_eventmanager: enter in %s mode", d411 1 a411 1 for (t = pth_pqueue_head(&pth_WQ); t != NULL; d413 1 a413 1 d449 1 a449 1 pth_util_fds_merge(ev->ev_args.SELECT.nfd, d485 1 a485 1 this_occurred = TRUE; d499 1 a499 1 this_occurred = TRUE; d504 1 a504 1 this_occurred = TRUE; d510 1 a510 1 this_occurred = TRUE; d514 1 a514 1 this_occurred = TRUE; d521 1 a521 1 if ( ( ev->ev_args.TID.tid == NULL d523 1 a523 1 || ( ev->ev_args.TID.tid != NULL d525 1 a525 1 this_occurred = TRUE; d530 2 a531 2 while ( (pid = pth_sc(waitpid)(ev->ev_args.PID.pid, ev->ev_args.PID.status, d536 1 a536 1 this_occurred = TRUE; d541 1 a541 1 this_occurred = TRUE; d558 1 a558 1 /* do a polling with immediate timeout, d597 1 a597 1 /* now do the polling for filedescriptor I/O and timers d601 2 a602 2 while ((rc = pth_sc(select)(fdmax+1, &rfds, &wfds, &efds, pdelay)) < 0 && errno == EINTR) ; d612 1 a612 1 pth_debug2("pth_sched_eventmanager: [timeout] event occurred for thread \"%s\"", d622 1 a622 1 d636 1 a636 1 t = pth_pqueue_head(&pth_WQ); d645 3 a647 3 /* * Late handling for still not occured events */ d664 1 a664 1 if (pth_util_fds_test(ev->ev_args.SELECT.nfd, d668 1 a668 1 n = pth_util_fds_select(ev->ev_args.SELECT.nfd, d695 1 a695 1 /* d725 2 a726 2 /* @ 1.64 log @*** empty log message *** @ text @d2 1 a2 2 ** pth_sched.c -- Pth thread scheduler ** d22 2 @ 1.64.2.1 log @*** empty log message *** @ text @d2 2 a3 1 ** GNU Pth - The GNU Portable Threads a22 2 ** ** pth_sched.c: Pth thread scheduler, the real heart of Pth @ 1.63 log @*** empty log message *** @ text @d12 1 a12 1 ** version 2 of the License, or (at your option) any later version. @ 1.62 log @*** empty log message *** @ text @d194 1 a194 1 "no more thread available to schedule!?!?\n"); @ 1.61 log @*** empty log message *** @ text @d52 2 a53 1 perror("pipe"); d192 5 @ 1.60 log @*** empty log message *** @ text @d10 1 a10 1 ** modify it under the terms of the GNU Library General Public d17 1 a17 1 ** Library General Public License for more details. d19 1 a19 1 ** You should have received a copy of the GNU Library General Public @ 1.59 log @*** empty log message *** @ text @d163 1 a163 1 sigprocmask(SIG_SETMASK, &sigs, NULL); d578 1 a578 1 memset((void *)&sa, 0, sizeof(struct sigaction)); d580 1 a580 1 sa.sa_handler = pth_sched_eventmanager_sighandler; d588 1 a588 1 sigprocmask(SIG_SETMASK, &pth_sigblock, &oss); d598 1 a598 1 sigprocmask(SIG_SETMASK, &oss, NULL); @ 1.58 log @*** empty log message *** @ text @d178 2 a179 2 pth_pqueue_insert(&pth_RQ, PTH_PRIO_MAX, t); pth_debug2("pth_scheduler: new thread \"%s\" moved to ready queue", t->name); @ 1.57 log @*** empty log message *** @ text @d29 5 a33 5 intern pth_t pth_main; /* the main thread */ intern pth_t pth_sched; /* the permanent scheduler thread */ intern pth_t pth_current; /* the currently running thread */ intern pth_pqueue_t pth_NQ; /* queue of new threads */ intern pth_pqueue_t pth_RQ; /* queue of threads ready to run */ d35 2 a36 2 intern pth_pqueue_t pth_DQ; /* queue of terminated threads */ intern float pth_loadval; /* average scheduler load value */ d38 2 a39 2 static int pth_sigpipe[2]; /* internal signal occurrence pipe */ static sigset_t pth_sigpending; /* mask of pending signals */ d41 2 a42 2 static sigset_t pth_sigcatch; /* mask of signals we have to catch */ static sigset_t pth_sigraised; /* mask of raised signals */ @ 1.56 log @*** empty log message *** @ text @d130 1 a130 1 pth_time_t t; \ d133 1 a133 1 pth_time_set(&t, (now)); \ d136 2 a137 2 pth_time_sub(&t, &pth_loadtickgap); \ } while (pth_time_cmp(&t, &pth_loadticknext) >= 0); \ @ 1.55 log @*** empty log message *** @ text @d113 27 a139 27 /* update the average scheduler load */ intern void pth_scheduler_load(pth_time_t *now) { pth_time_t t; int numready; /* * We're called on every context switch, but we have to adjust the average * load value every second, only. When we're called more than once per * second we handle this by just calculating anything once and then do * NOPs until the next ticks is over. When the scheduler waited for more * than once second (or a thread CPU burst lasted for more than once * second) we simulate the missing calculations. That's no problem because * we can assume that the number of ready threads then wasn't changed * dramatically (or more context switched would have been occurred and we * would have been given more chances to operate). The actual average load * is calculated through an exponential average formula. */ if (pth_time_cmp(now, &pth_loadticknext) >= 0) { numready = pth_pqueue_elements(&pth_RQ); pth_time_set(&t, now); do { pth_loadval = (numready*0.25) + (pth_loadval*0.75); pth_time_sub(&t, &pth_loadtickgap); } while (pth_time_cmp(&t, &pth_loadticknext) >= 0); pth_time_set(&pth_loadticknext, now); pth_time_add(&pth_loadticknext, &pth_loadtickgap); a140 2 return; } @ 1.54 log @*** empty log message *** @ text @d24 3 a26 1 @ 1.53 log @*** empty log message *** @ text @d656 1 a656 1 if (ev->ev_type == PTH_EVENT_SELECT) { @ 1.52 log @*** empty log message *** @ text @d287 1 a287 1 fprintf(stderr, "** STACK OVERFLOW: thread 0x%lx (\"%s\")\n", @ 1.51 log @*** empty log message *** @ text @d731 2 a732 2 pth_debug2("pth_scheduler: thread \"%s\" moved from waiting to ready queue", tlast->name); @ 1.50 log @*** empty log message *** @ text @d53 2 a54 2 pth_nonblocking(pth_sigpipe[0]); pth_nonblocking(pth_sigpipe[1]); @ 1.49 log @*** empty log message *** @ text @d638 3 d688 16 @ 1.48 log @*** empty log message *** @ text @d700 8 a707 1 /* move last thread to ready queue when any events occurred for it */ d711 1 a711 1 pth_pqueue_insert(&pth_RQ, tlast->prio, tlast); @ 1.47 log @*** empty log message *** @ text @d501 1 a501 1 if (!(ev->ev_args.COND.cond->cn_state & PTH_COND_SIGNALED)) { @ 1.46 log @*** empty log message *** @ text @d382 3 d594 1 a594 1 while ((rc = pth_sc(select)(fdmax+1, &rfds, NULL, NULL, pdelay)) < 0 d709 2 @ 1.45 log @*** empty log message *** @ text @d520 5 a524 2 pid = pth_sc(waitpid)(ev->ev_args.PID.pid, ev->ev_args.PID.status, ev->ev_args.PID.flags|WNOHANG); @ 1.44 log @*** empty log message *** @ text @d216 2 a217 2 pth_debug3("pth_scheduler: switching to thread 0x%x (\"%s\")", (unsigned int)pth_current, pth_current->name); d232 2 a233 2 pth_debug3("pth_scheduler: cameback from thread 0x%x (\"%s\")", (unsigned int)pth_current, pth_current->name); d279 2 a280 2 pth_debug3("pth_scheduler: stack overflow detected for thread 0x%x (\"%s\")", (unsigned int)pth_current, pth_current->name); d287 2 a288 3 fprintf(stderr, "** STACK OVERFLOW: thread 0x%x (\"%s\")\n", (unsigned int)((unsigned long)pth_current), pth_current->name); @ 1.43 log @*** empty log message *** @ text @d358 1 a358 1 intern void pth_sched_eventmanager(pth_time_t *now, int poll) d542 1 a542 1 poll = TRUE; d545 1 a545 1 if (poll) { d588 1 a588 1 if (!(poll && fdmax == -1)) d599 1 a599 1 if (!poll && rc == 0 && nexttimer_ev != NULL) { d606 1 a606 1 if (!poll && rc > 0 && FD_ISSET(pth_sigpipe[0], &rfds)) { @ 1.42 log @*** empty log message *** @ text @d521 2 a522 2 pid = waitpid(ev->ev_args.PID.pid, ev->ev_args.PID.status, ev->ev_args.PID.flags|WNOHANG); d565 1 a565 1 while (read(pth_sigpipe[0], minibuf, sizeof(minibuf)) > 0) ; d589 1 a589 1 while ((rc = select(fdmax+1, &rfds, NULL, NULL, pdelay)) < 0 d716 1 a716 1 write(pth_sigpipe[1], &c, sizeof(char)); @ 1.41 log @*** empty log message *** @ text @d381 1 d436 11 d634 1 a634 1 /* filedescriptor I/O */ d645 17 @ 1.40 log @*** empty log message *** @ text @d2 1 a2 1 ** pth_sched.c -- PTH thread scheduler @ 1.39 log @*** empty log message *** @ text @d6 2 a7 2 ** This file is part of PTH, a non-preemptive thread scheduling library ** which can be found at http://www.gnu.org/software/pth/. @ 1.38 log @*** empty log message *** @ text @d288 2 a289 1 (unsigned int)pth_current, pth_current->name); @ 1.37 log @*** empty log message *** @ text @d7 1 a7 1 ** which can be found at http://www.engelschall.com/sw/pth/. @ 1.36 log @*** empty log message *** @ text @d150 1 d195 18 d214 1 a214 1 * and do a context switch to it d245 30 d438 8 @ 1.35 log @*** empty log message *** @ text @d158 1 a158 1 pth_sched->state = pth_state_scheduler; d176 1 a176 1 t->state = pth_state_ready; d252 1 a252 1 pth_current->state = pth_state_dead; d260 1 a260 1 if (pth_current->state == pth_state_dead) { d273 1 a273 1 if (pth_current != NULL && pth_current->state == pth_state_waiting) { d611 1 a611 1 tlast->state = pth_state_ready; @ 1.34 log @*** empty log message *** @ text @d258 1 a258 1 * When last thread is now marked as dead, kick it out d262 1 a262 1 if (pth_current->flags & PTH_FLAG_NOJOIN) @ 1.33 log @*** empty log message *** @ text @d424 1 a424 1 if (!(ev->ev_args.MUTEX.mutex->state & PTH_MUTEX_LOCKED)) d426 13 @ 1.32 log @*** empty log message *** @ text @d422 5 @ 1.31 log @*** empty log message *** @ text @d581 2 a582 1 if (t->cancelreq == TRUE) d584 1 @ 1.30 log @*** empty log message *** @ text @d359 4 d444 1 a444 1 /* tag event when it has occured */ d579 4 @ 1.29 log @*** empty log message *** @ text @d148 2 d224 32 @ 1.28 log @*** empty log message *** @ text @d354 1 a354 1 pth_sched_sigdelete(sig); a567 41 return; } intern int pth_sched_sigdelete(int sig) { sigset_t ss, oss; struct sigaction sa, osa; /* check status of signal */ sigemptyset(&ss); sigaddset(&ss, sig); sigprocmask(SIG_BLOCK, &ss, &oss); sigpending(&ss); if (!sigismember(&ss, sig)) { sigprocmask(SIG_SETMASK, &oss, NULL); return FALSE; } /* set signal action to our dummy handler */ memset((void *)&sa, 0, sizeof(struct sigaction)); sigfillset(&sa.sa_mask); sa.sa_handler = pth_sched_sigdelete_sighandler; if (sigaction(sig, &sa, &osa) != 0) { sigprocmask(SIG_SETMASK, &oss, NULL); return FALSE; } /* now let signal be delivered */ sigfillset(&ss); sigdelset(&ss, sig); sigsuspend(&ss); /* restore signal mask and handler */ sigaction(sig, &osa, NULL); sigprocmask(SIG_SETMASK, &oss, NULL); return TRUE; } intern void pth_sched_sigdelete_sighandler(int sig) { /* nop */ @ 1.27 log @*** empty log message *** @ text @d27 8 a34 8 intern pth_t pth_main; /* the main thread */ intern pth_t pth_sched; /* the permanent scheduler thread */ intern pth_t pth_current; /* the currently running thread */ intern pth_pqueue_t pth_NQ; /* queue of new threads */ intern pth_pqueue_t pth_RQ; /* queue of threads ready to run */ intern pth_pqueue_t pth_WQ; /* queue of threads waiting for an event */ intern pth_pqueue_t pth_DQ; /* queue of terminated threads */ intern float pth_loadval; /* average scheduler load value */ d42 2 a43 8 static pth_time_t pth_loadticknext; static pth_time_t pth_loadtickgap = PTH_TIME(1,0); static void pth_scheduler_load(pth_time_t *now); static void pth_sched_eventmanager(pth_time_t *now, int poll); static void pth_sched_eventmanager_sighandler(int sig); static int pth_sched_sigdelete(int sig); static void pth_sched_sigdelete_sighandler(int sig); d112 1 a112 1 static void pth_scheduler_load(pth_time_t *now) d274 1 a274 1 static void pth_sched_eventmanager(pth_time_t *now, int poll) d290 1 a290 1 sigset_t ss, oss; d558 1 a558 1 static void pth_sched_eventmanager_sighandler(int sig) d571 1 a571 1 static int pth_sched_sigdelete(int sig) d606 1 a606 1 static void pth_sched_sigdelete_sighandler(int sig) @ 1.26 log @*** empty log message *** @ text @d36 6 d47 3 d54 9 d65 2 d71 2 d83 1 d87 2 d92 2 d97 2 d105 12 d151 1 a151 1 sigset_t blockall; d164 4 d203 1 d206 1 d211 2 a212 1 /* switch context */ d214 1 d296 4 a299 1 sigset_t sigs; d302 1 d310 5 a314 3 /* determine pending signals */ if (sigpending(&sigs) < 0) sigemptyset(&sigs); d325 6 d353 17 a369 4 /* Signal */ else if (ev->ev_type == PTH_EVENT_SIG) { if (sigismember(&sigs, ev->ev_args.SIG.sig)) this_occurred = TRUE; d444 21 d472 6 d484 6 d492 1 a492 1 if (rc == -1) { d507 2 a508 1 /* do the late handling of the fd I/O events in the waiting event ring */ d514 1 d527 15 d561 54 @ 1.25 log @*** empty log message *** @ text @d119 1 d122 1 a122 3 /* block all signals in the scheduler thread */ sigfillset(&blockall); sigprocmask(SIG_SETMASK, &blockall, NULL); @ 1.24 log @*** empty log message *** @ text @d115 3 a117 1 /* bootstrapping */ d119 3 d124 1 a125 1 pth_sched->state = pth_state_scheduler; d127 3 a129 1 /* endless scheduler loop */ @ 1.23 log @*** empty log message *** @ text @d110 1 d117 2 @ 1.22 log @*** empty log message *** @ text @d238 1 d248 4 d274 1 a274 1 if (ev->ev_goal == PTH_UNTIL_FD_READABLE) d276 1 a276 1 else if (ev->ev_goal == PTH_UNTIL_FD_WRITEABLE) d278 1 a278 1 else if (ev->ev_goal == PTH_UNTIL_FD_EXCEPTION) d283 5 d398 1 a398 1 if ( ( ev->ev_goal == PTH_UNTIL_FD_READABLE d400 1 a400 1 || ( ev->ev_goal == PTH_UNTIL_FD_WRITEABLE d402 1 a402 1 || ( ev->ev_goal == PTH_UNTIL_FD_EXCEPTION @ 1.21 log @*** empty log message *** @ text @d269 1 a269 1 if (ev->ev_goal == PTH_UNTIL_READABLE) d271 1 a271 1 else if (ev->ev_goal == PTH_UNTIL_WRITEABLE) d273 1 a273 1 else if (ev->ev_goal == PTH_UNTIL_EXCEPTION) d388 1 a388 1 if ( ( ev->ev_goal == PTH_UNTIL_READABLE d390 1 a390 1 || ( ev->ev_goal == PTH_UNTIL_WRITEABLE d392 1 a392 1 || ( ev->ev_goal == PTH_UNTIL_EXCEPTION @ 1.20 log @*** empty log message *** @ text @d20 1 a20 1 ** License along with this library; if not, write to the Free @ 1.19 log @*** empty log message *** @ text @a40 1 static void pth_sched_eventoccurred(pth_t t, pth_event_t ev); a227 1 pth_event_t evo; d257 1 a257 2 evh = *t->events_waiting; if (evh == NULL) a258 1 ev = evh; d260 1 d262 28 a289 28 this_occurred = FALSE; if (ev->ev_occurred) this_occurred = TRUE; /* Filedescriptor I/O */ if (ev->ev_type == PTH_EVENT_FD) { /* filedescriptors are checked later all at once. Here we only assemble them in the fd sets */ if (ev->ev_goal == PTH_UNTIL_READABLE) FD_SET(ev->ev_args.FD.fd, &rfds); else if (ev->ev_goal == PTH_UNTIL_WRITEABLE) FD_SET(ev->ev_args.FD.fd, &wfds); else if (ev->ev_goal == PTH_UNTIL_EXCEPTION) FD_SET(ev->ev_args.FD.fd, &efds); if (fdmax < ev->ev_args.FD.fd) fdmax = ev->ev_args.FD.fd; } /* Timer */ else if (ev->ev_type == PTH_EVENT_TIME) { if (pth_time_cmp(&(ev->ev_args.TIME.tv), now) < 0) this_occurred = TRUE; else { /* remember the timer which will be elapsed next */ if ((nexttimer_thread == NULL && nexttimer_ev == NULL) || pth_time_cmp(&(ev->ev_args.TIME.tv), &nexttimer_value) < 0) { nexttimer_thread = t; nexttimer_ev = ev; pth_time_set(&nexttimer_value, &(ev->ev_args.TIME.tv)); d292 26 a317 27 } /* Message Port Arrivals */ else if (ev->ev_type == PTH_EVENT_MSG) { if (!pth_ring_empty(&(ev->ev_args.MSG.mp->mp_queue))) this_occurred = TRUE; } /* Thread Termination */ else if (ev->ev_type == PTH_EVENT_TID) { if ( ( ev->ev_args.TID.tid == NULL && pth_pqueue_elements(&pth_DQ) > 0) || ( ev->ev_args.TID.tid != NULL && ev->ev_args.TID.tid->state == ev->ev_goal)) this_occurred = TRUE; } /* Process Termination */ else if (ev->ev_type == PTH_EVENT_PID) { pid_t pid; pid = waitpid(ev->ev_args.PID.pid, ev->ev_args.PID.status, ev->ev_args.PID.flags|WNOHANG); if (pid > 0) this_occurred = TRUE; } /* Custom Event Function */ else if (ev->ev_type == PTH_EVENT_FUNC) { if (ev->ev_args.FUNC.func(ev->ev_args.FUNC.func_arg)) this_occurred = TRUE; } d319 6 a324 9 /* move to next event */ evo = ev; ev = ev->ev_next; /* now move event from waiting to occurred event ring */ if (this_occurred) { pth_debug2("pth_sched_eventmanager: event occurred for thread \"%s\"", t->name); pth_sched_eventoccurred(t, evo); any_occurred = TRUE; d326 1 a326 2 } while (ev != NULL && ev != evh); d359 5 a363 2 if (!poll && rc == 0 && nexttimer_ev != NULL) pth_sched_eventoccurred(nexttimer_thread, nexttimer_ev); d382 3 a384 3 evh = *t->events_waiting; if (evh != NULL) { ev = evh; d386 12 a397 10 if (ev->ev_type == PTH_EVENT_FD) { if ( ( ev->ev_goal == PTH_UNTIL_READABLE && FD_ISSET(ev->ev_args.FD.fd, &rfds)) || ( ev->ev_goal == PTH_UNTIL_WRITEABLE && FD_ISSET(ev->ev_args.FD.fd, &wfds)) || ( ev->ev_goal == PTH_UNTIL_EXCEPTION && FD_ISSET(ev->ev_args.FD.fd, &efds)) ) { pth_debug2("pth_sched_eventmanager: " "event occurred for thread \"%s\"", t->name); pth_sched_eventoccurred(t, ev); d400 3 a402 1 } while (ev != NULL && (ev = ev->ev_next) != evh); d410 1 a410 1 if (*tlast->events_occurred != NULL) { a416 29 } return; } static void pth_sched_eventoccurred(pth_t t, pth_event_t ev) { pth_event_t evo; /* mark event as occurred */ ev->ev_occurred = TRUE; /* remove event from waiting event ring */ if (ev->ev_next == ev) *t->events_waiting = NULL; else { if (ev == *t->events_waiting) *t->events_waiting = ev->ev_next; ev->ev_prev->ev_next = ev->ev_next; ev->ev_next->ev_prev = ev->ev_prev; } /* add event thread to occurred event ring */ if (*t->events_occurred == NULL) *t->events_occurred = ev; else { evo = *t->events_occurred; evo->ev_prev->ev_next = ev; evo->ev_prev = ev; ev->ev_next = evo; ev->ev_prev = evo->ev_prev; *t->events_occurred = ev; @ 1.18 log @*** empty log message *** @ text @d303 4 a306 1 if (ev->ev_args.TID.tid->state == ev->ev_goal) @ 1.17 log @*** empty log message *** @ text @d27 8 a34 8 pth_t pth_main; /* the main thread */ pth_t pth_sched; /* the permanent scheduler thread */ pth_t pth_current; /* the currently running thread */ pth_pqueue_t pth_NQ; /* queue of new threads */ pth_pqueue_t pth_RQ; /* queue of threads ready to run */ pth_pqueue_t pth_WQ; /* queue of threads waiting for an event */ pth_pqueue_t pth_DQ; /* queue of terminated threads */ float pth_loadval; /* average scheduler load value */ d44 1 a44 1 void pth_scheduler_init(void) d58 1 a58 1 void pth_scheduler_drop(void) d109 1 a109 1 void *pth_scheduler(void *dummy) @ 1.16 log @*** empty log message *** @ text @d215 2 @ 1.15 log @*** empty log message *** @ text @d41 1 a41 1 static void pth_sched_eventoccured(pth_t t, pth_event_t ev); d91 1 a91 1 * dramatically (or more context switched would have been occured and we d206 1 a206 1 * events occured and move them to the ready queue. But wait only when d218 1 a218 1 * Look whether some events already occured and move d231 2 a232 2 int this_occured; int any_occured; d253 1 a253 1 any_occured = FALSE; d261 1 a261 1 /* ...check whether events occured */ d263 3 a265 3 this_occured = FALSE; if (ev->ev_occured) this_occured = TRUE; d283 1 a283 1 this_occured = TRUE; d297 1 a297 1 this_occured = TRUE; d302 1 a302 1 this_occured = TRUE; d310 1 a310 1 this_occured = TRUE; d315 1 a315 1 this_occured = TRUE; d322 5 a326 5 /* now move event from waiting to occured event ring */ if (this_occured) { pth_debug2("pth_sched_eventmanager: event occured for thread \"%s\"", t->name); pth_sched_eventoccured(t, evo); any_occured = TRUE; d331 1 a331 1 if (any_occured) d363 1 a363 1 pth_sched_eventoccured(nexttimer_thread, nexttimer_ev); d365 1 a365 1 /* when an error occured, avoid confusion in the cleanup loop */ d374 1 a374 1 additionally when a thread has one occured event, we move it from the d394 2 a395 2 "event occured for thread \"%s\"", t->name); pth_sched_eventoccured(t, ev); d405 2 a406 2 /* move last thread to ready queue when any events occured for it */ if (*tlast->events_occured != NULL) { d417 1 a417 1 static void pth_sched_eventoccured(pth_t t, pth_event_t ev) d421 2 a422 2 /* mark event as occured */ ev->ev_occured = TRUE; d432 3 a434 3 /* add event thread to occured event ring */ if (*t->events_occured == NULL) *t->events_occured = ev; d436 1 a436 1 evo = *t->events_occured; d441 1 a441 1 *t->events_occured = ev; @ 1.14 log @*** empty log message *** @ text @d177 3 a179 1 if (pth_current->joinable) a180 2 else pth_tcb_free(pth_current); @ 1.13 log @*** empty log message *** @ text @d6 1 a6 1 ** This file is part of PTH, a non-preemtive thread scheduling library @ 1.12 log @*** empty log message *** @ text @d57 2 a58 2 /* kill/re-initialize the scheduler ingredients */ void pth_scheduler_kill(void) d64 1 d67 1 d70 1 d73 1 a73 1 pth_scheduler_init(); @ 1.11 log @*** empty log message *** @ text @d34 1 a34 1 float pth_load; /* average scheduler load */ d52 1 a52 1 pth_load = 1.0; d96 1 a96 1 pth_load = (numready*0.25) + (pth_load*0.75); @ 1.10 log @*** empty log message *** @ text @d34 1 d36 4 d43 1 d52 2 d57 1 d74 32 a105 1 /* the heart of this library: the tread scheduler */ d130 5 a210 1 @ 1.9 log @*** empty log message *** @ text @d27 1 @ 1.8 log @*** empty log message *** @ text @a0 40 /* ==================================================================== * Copyright (c) 1999 Ralf S. Engelschall. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. All advertising materials mentioning features or use of this * software must display the following acknowledgment: * "This product includes software developed by * Ralf S. Engelschall ." * * 4. Redistributions of any form whatsoever must retain the following * acknowledgment: * "This product includes software developed by * Ralf S. Engelschall ." * * THIS SOFTWARE IS PROVIDED BY RALF S. ENGELSCHALL ``AS IS'' AND ANY * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL RALF S. ENGELSCHALL OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== */ d2 21 a22 2 ** Non-Preemtive Scheduler Library (PTH) ** pth_sched.c -- scheduler code @ 1.7 log @*** empty log message *** @ text @d104 1 d381 1 @ 1.6 log @*** empty log message *** @ text @d204 1 d225 1 d266 5 d298 1 d303 2 d322 1 a322 1 i.e. wait the fd sets only with blocking */ d328 4 a331 2 while ((rc = select(fdmax+1, &rfds, NULL, NULL, pdelay)) < 0 && errno == EINTR) ; @ 1.5 log @*** empty log message *** @ text @d322 1 a322 3 if (!poll && rc == 0 && nexttimer_ev != NULL) { pth_debug4("pth_sched_eventmanager: select-timer elapsed for thread \"%s\" %d %d", nexttimer_thread->name, pdelay->tv_sec, pdelay->tv_usec); a323 1 } d354 1 a354 1 "fd event occured for thread \"%s\"", t->name); @ 1.4 log @*** empty log message *** @ text @a202 1 int any_occured; d288 2 a289 1 if (this_occured) d291 1 d322 3 a324 1 if (rc == 0 && nexttimer_ev != NULL) d326 1 d356 2 a358 1 any_occured = TRUE; a404 1 pth_debug2("pth_sched_eventoccured: event occured for thread \"%s\"", t->name); @ 1.3 log @*** empty log message *** @ text @a325 2 perror("select"); exit(0); @ 1.2 log @*** empty log message *** @ text @d55 2 a56 1 static void pth_scheduler_eventmanager(pth_time_t *now); a89 1 pth_time_t now; d176 3 a178 3 * Manage the events in the waiting queue, i.e. decide * whether their events occured and move them to the * ready queue. d180 5 a184 1 pth_scheduler_eventmanager(&snapshot); a185 16 /* * Now finally we have to be carefully: Before we allow the next * scheduler round to occur we have to make sure not all(!) threads * are still waiting. If so, the scheduler has to wait now, itself. * After a short time we can check for new occured events and when * still all threads are waiting, we will wait again. Until one * thread now is ready... */ if ( pth_pqueue_elements(&pth_RQ) == 0 && pth_pqueue_elements(&pth_NQ) == 0) { while (pth_pqueue_elements(&pth_RQ) == 0) { pth_time_usleep(10000); /* 1/10 s */ pth_time_set(&now, PTH_TIME_NOW); pth_scheduler_eventmanager(&now); } } d193 1 a193 1 static void pth_scheduler_eventmanager(pth_time_t *now) d195 3 d202 1 d209 1 a210 1 int n; d213 1 a213 1 /* first pre-assemble filedescriptors */ d218 10 a227 3 for (n = pth_pqueue_elements(&pth_WQ); n > 0; n--) { t = pth_pqueue_delmax(&pth_WQ); /* look at events */ d232 1 d234 1 d236 3 a238 1 continue; d240 2 a241 2 if (fdmax < ev->ev_args.FD.fd) fdmax = ev->ev_args.FD.fd; d248 2 d251 1 a251 33 } while (ev != NULL && (ev = ev->ev_next) != evh); pth_pqueue_insert(&pth_WQ, PTH_PRIO_MIN, t); } /* globally pre-check the status of all filedescriptors */ if (fdmax > -1) { delay.tv_sec = 0; delay.tv_usec = 0; while ((rc = select(fdmax+1, &rfds, &wfds, &efds, &delay)) < 0 && errno == EINTR) ; } /* foreach thread in the waiting queue */ for (n = pth_pqueue_elements(&pth_WQ); n > 0; n--) { t = pth_pqueue_delmax(&pth_WQ); /* look at pending events */ evh = *t->events_waiting; if (evh == NULL) continue; ev = evh; any_occured = FALSE; do { this_occured = FALSE; if (ev->ev_occured) this_occured = TRUE; if (ev->ev_type == PTH_EVENT_FD) { if ( ( ev->ev_goal == PTH_UNTIL_READABLE && FD_ISSET(ev->ev_args.FD.fd, &rfds)) || ( ev->ev_goal == PTH_UNTIL_WRITEABLE && FD_ISSET(ev->ev_args.FD.fd, &wfds)) || ( ev->ev_goal == PTH_UNTIL_EXCEPTION && FD_ISSET(ev->ev_args.FD.fd, &efds)) ) this_occured = TRUE; } d255 9 d265 1 d270 1 d278 1 d283 74 a356 12 if (this_occured) { pth_debug2("pth_scheduler: event occured for thread \"%s\"", t->name); any_occured = TRUE; ev->ev_occured = TRUE; /* remove from waiting event ring */ if (ev->ev_next == ev) *t->events_waiting = NULL; else { if (ev == *t->events_waiting) *t->events_waiting = ev->ev_next; ev->ev_prev->ev_next = ev->ev_next; ev->ev_next->ev_prev = ev->ev_prev; d358 2 a359 13 /* add to occured event ring */ if (*t->events_occured == NULL) *t->events_occured = ev; else { evo = *t->events_occured; evo->ev_prev->ev_next = ev; evo->ev_prev = ev; ev->ev_next = evo; ev->ev_prev = evo->ev_prev; *t->events_occured = ev; } } } while (ev != NULL && (ev = ev->ev_next) != evh); d361 8 a368 3 /* move thread to ready queue when events occured for it */ if (any_occured) { pth_pqueue_insert(&pth_RQ, t->prio, t); d370 1 a370 2 t->name); continue; d372 7 d380 21 a400 2 /* move back to end of queue */ pth_pqueue_insert(&pth_WQ, PTH_PRIO_MIN, t); d402 1 @ 1.1 log @Initial revision @ text @d193 1 a193 1 pth_usleep(10000); /* 1/10 s */ @ 1.1.1.1 log @Import of PTH into CVS @ text @@