⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 pth_sched.c

📁 Linux下的中文输入法
💻 C
📖 第 1 页 / 共 3 页
字号:
/***  GNU Pth - The GNU Portable Threads**  Copyright (c) 1999-2004 Ralf S. Engelschall <rse@engelschall.com>****  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 <rse@engelschall.com>.****  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 */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -