[BACK]Return to kern_workq.c CVS log [TXT][DIR] Up to [local] / sys / kern

Annotation of sys/kern/kern_workq.c, Revision 1.1

1.1     ! nbrk        1: /*     $OpenBSD: kern_workq.c,v 1.3 2007/06/11 22:15:11 thib Exp $ */
        !             2:
        !             3: /*
        !             4:  * Copyright (c) 2007 David Gwynne <dlg@openbsd.org>
        !             5:  * Copyright (c) 2007 Ted Unangst <tedu@openbsd.org>
        !             6:  *
        !             7:  * Permission to use, copy, modify, and distribute this software for any
        !             8:  * purpose with or without fee is hereby granted, provided that the above
        !             9:  * copyright notice and this permission notice appear in all copies.
        !            10:  *
        !            11:  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
        !            12:  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
        !            13:  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
        !            14:  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
        !            15:  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
        !            16:  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
        !            17:  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
        !            18:  */
        !            19:
        !            20: #include <sys/param.h>
        !            21: #include <sys/systm.h>
        !            22: #include <sys/malloc.h>
        !            23: #include <sys/pool.h>
        !            24: #include <sys/queue.h>
        !            25: #include <sys/kthread.h>
        !            26: #include <sys/workq.h>
        !            27:
        !            28: struct workq_task {
        !            29:        int             wqt_flags;
        !            30:        workq_fn        wqt_func;
        !            31:        void            *wqt_arg1;
        !            32:        void            *wqt_arg2;
        !            33:
        !            34:        SIMPLEQ_ENTRY(workq_task) wqt_entry;
        !            35: };
        !            36:
        !            37: struct workq {
        !            38:        int             wq_flags;
        !            39: #define WQ_F_RUNNING           (1<<0)
        !            40:        int             wq_running;
        !            41:        int             wq_busy;
        !            42:        int             wq_max;
        !            43:        const char      *wq_name;
        !            44:
        !            45:        SIMPLEQ_HEAD(, workq_task) wq_tasklist;
        !            46: };
        !            47:
        !            48: struct pool    workq_task_pool;
        !            49: struct workq   workq_syswq = {
        !            50:        WQ_F_RUNNING,
        !            51:        0,
        !            52:        0,
        !            53:        1,
        !            54:        "syswq"
        !            55: };
        !            56:
        !            57: void           workq_init(void); /* called in init_main.c */
        !            58: void           workq_init_syswq(void *);
        !            59: void           workq_create_thread(void *);
        !            60: void           workq_thread(void *);
        !            61:
        !            62: void
        !            63: workq_init(void)
        !            64: {
        !            65:        pool_init(&workq_task_pool, sizeof(struct workq_task), 0, 0,
        !            66:            0, "wqtasks", NULL);
        !            67:
        !            68:        SIMPLEQ_INIT(&workq_syswq.wq_tasklist);
        !            69:        kthread_create_deferred(workq_init_syswq, NULL);
        !            70: }
        !            71:
        !            72: void
        !            73: workq_init_syswq(void *arg)
        !            74: {
        !            75:        if (kthread_create(workq_thread, &workq_syswq, NULL, "%s",
        !            76:            workq_syswq.wq_name) != 0)
        !            77:                panic("unable to create system work queue thread");
        !            78:
        !            79:        workq_syswq.wq_running++;
        !            80: }
        !            81:
        !            82: struct workq *
        !            83: workq_create(const char *name, int maxqs)
        !            84: {
        !            85:        struct workq *wq;
        !            86:
        !            87:        wq = malloc(sizeof(*wq), M_DEVBUF, M_NOWAIT);
        !            88:        if (wq == NULL)
        !            89:                return (NULL);
        !            90:
        !            91:        wq->wq_flags = WQ_F_RUNNING;
        !            92:        wq->wq_running = 0;
        !            93:        wq->wq_busy = 0;
        !            94:        wq->wq_max = maxqs;
        !            95:        wq->wq_name = name;
        !            96:        SIMPLEQ_INIT(&wq->wq_tasklist);
        !            97:
        !            98:        /* try to create a thread to guarantee that tasks will be serviced */
        !            99:        kthread_create_deferred(workq_create_thread, wq);
        !           100:
        !           101:        return (wq);
        !           102: }
        !           103:
        !           104: void
        !           105: workq_destroy(struct workq *wq)
        !           106: {
        !           107:        int                     s;
        !           108:
        !           109:        s = splhigh();
        !           110:
        !           111:        wq->wq_flags &= ~WQ_F_RUNNING;
        !           112:        while (wq->wq_running != 0) {
        !           113:                wakeup(wq);
        !           114:                tsleep(&wq->wq_running, PWAIT, "wqdestroy", 0);
        !           115:        }
        !           116:
        !           117:        splx(s);
        !           118:
        !           119:        free(wq, M_DEVBUF);
        !           120: }
        !           121:
        !           122: int
        !           123: workq_add_task(struct workq *wq, int flags, workq_fn func,
        !           124:     void *a1, void *a2)
        !           125: {
        !           126:        struct workq_task       *wqt;
        !           127:        int                     wake = 1;
        !           128:        int                     s;
        !           129:
        !           130:        if (wq == NULL)
        !           131:                wq = &workq_syswq;
        !           132:
        !           133:        s = splhigh();
        !           134:        wqt = pool_get(&workq_task_pool, (flags & WQ_WAITOK) ?
        !           135:            PR_WAITOK : PR_NOWAIT);
        !           136:        splx(s);
        !           137:        if (!wqt)
        !           138:                return (ENOMEM);
        !           139:
        !           140:        wqt->wqt_flags = flags;
        !           141:        wqt->wqt_func = func;
        !           142:        wqt->wqt_arg1 = a1;
        !           143:        wqt->wqt_arg2 = a2;
        !           144:
        !           145:        s = splhigh();
        !           146:        SIMPLEQ_INSERT_TAIL(&wq->wq_tasklist, wqt, wqt_entry);
        !           147:        if ((wq->wq_running < wq->wq_max) && (wq->wq_running == wq->wq_busy)) {
        !           148:                kthread_create_deferred(workq_create_thread, wq);
        !           149:                wake = 0;
        !           150:        }
        !           151:        splx(s);
        !           152:
        !           153:        if (wake)
        !           154:                wakeup_one(wq);
        !           155:
        !           156:        return (0);
        !           157: }
        !           158:
        !           159: void
        !           160: workq_create_thread(void *arg)
        !           161: {
        !           162:        struct workq            *wq = arg;
        !           163:        int                     rv;
        !           164:
        !           165:        rv = kthread_create(workq_thread, wq, NULL, "%s", wq->wq_name);
        !           166:        if (rv != 0) {
        !           167:                printf("unable to create \"%s\" workq thread\n", wq->wq_name);
        !           168:                return;
        !           169:        }
        !           170:
        !           171:        wq->wq_running++;
        !           172: }
        !           173:
        !           174: void
        !           175: workq_thread(void *arg)
        !           176: {
        !           177:        struct workq            *wq = arg;
        !           178:        struct workq_task       *wqt;
        !           179:        int                     s;
        !           180:
        !           181:        s = splhigh();
        !           182:        while (wq->wq_flags & WQ_F_RUNNING) {
        !           183:                while ((wqt = SIMPLEQ_FIRST(&wq->wq_tasklist)) != NULL) {
        !           184:                        SIMPLEQ_REMOVE_HEAD(&wq->wq_tasklist, wqt_entry);
        !           185:                        wq->wq_busy++;
        !           186:                        splx(s);
        !           187:
        !           188:                        if (wqt->wqt_flags & WQ_MPSAFE)
        !           189:                                ;
        !           190:                        wqt->wqt_func(wqt->wqt_arg1, wqt->wqt_arg2);
        !           191:                        if (wqt->wqt_flags & WQ_MPSAFE)
        !           192:                                ;
        !           193:
        !           194:                        s = splhigh();
        !           195:                        wq->wq_busy--;
        !           196:                        pool_put(&workq_task_pool, wqt);
        !           197:                }
        !           198:                tsleep(wq, PWAIT, "bored", 0);
        !           199:        }
        !           200:        wq->wq_running--;
        !           201:        splx(s);
        !           202:        wakeup(&wq->wq_running);
        !           203:
        !           204:        kthread_exit(0);
        !           205: }

CVSweb