[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

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