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