Annotation of libaitsched/src/hooks.c, revision 1.2.2.1
1.1 misho 1: /*************************************************************************
2: * (C) 2011 AITNET ltd - Sofia/Bulgaria - <misho@aitbg.com>
3: * by Michael Pounov <misho@openbsd-bg.org>
4: *
5: * $Author: misho $
1.2.2.1 ! misho 6: * $Id: hooks.c,v 1.2 2011/10/04 12:34:33 misho Exp $
1.1 misho 7: *
8: **************************************************************************
9: The ELWIX and AITNET software is distributed under the following
10: terms:
11:
12: All of the documentation and software included in the ELWIX and AITNET
13: Releases is copyrighted by ELWIX - Sofia/Bulgaria <info@elwix.org>
14:
15: Copyright 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011
16: by Michael Pounov <misho@elwix.org>. All rights reserved.
17:
18: Redistribution and use in source and binary forms, with or without
19: modification, are permitted provided that the following conditions
20: are met:
21: 1. Redistributions of source code must retain the above copyright
22: notice, this list of conditions and the following disclaimer.
23: 2. Redistributions in binary form must reproduce the above copyright
24: notice, this list of conditions and the following disclaimer in the
25: documentation and/or other materials provided with the distribution.
26: 3. All advertising materials mentioning features or use of this software
27: must display the following acknowledgement:
28: This product includes software developed by Michael Pounov <misho@elwix.org>
29: ELWIX - Embedded LightWeight unIX and its contributors.
30: 4. Neither the name of AITNET nor the names of its contributors
31: may be used to endorse or promote products derived from this software
32: without specific prior written permission.
33:
34: THIS SOFTWARE IS PROVIDED BY AITNET AND CONTRIBUTORS ``AS IS'' AND
35: ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
36: IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
37: ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
38: FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
39: DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
40: OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
41: HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
42: LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
43: OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44: SUCH DAMAGE.
45: */
46: #include "global.h"
47: #include "hooks.h"
48:
49:
50: /*
51: * sched_hook_init() - Default INIT hook
52: * @root = root task
53: * @data = optional data if !=NULL
54: * return: <0 errors and 0 ok
55: */
56: void *
57: sched_hook_init(void *root, void *data)
58: {
59: sched_root_task_t *r = root;
60:
61: if (!r || r->root_data.iov_base || r->root_data.iov_len)
62: return (void*) -1;
63:
64: r->root_data.iov_base = malloc(sizeof(struct sched_IO));
65: if (!r->root_data.iov_base) {
66: LOGERR;
67: return (void*) -1;
68: } else {
69: r->root_data.iov_len = sizeof(struct sched_IO);
70: memset(r->root_data.iov_base, 0, r->root_data.iov_len);
71: }
72:
73: r->root_kq = kqueue();
74: if (r->root_kq == -1) {
75: LOGERR;
76: return (void*) -1;
77: }
78:
79: return NULL;
80: }
81:
82: /*
83: * sched_hook_fini() - Default FINI hook
84: * @root = root task
85: * @arg = unused
86: * return: <0 errors and 0 ok
87: */
88: void *
89: sched_hook_fini(void *root, void *arg __unused)
90: {
91: sched_root_task_t *r = root;
92:
93: if (!r)
94: return (void*) -1;
95:
96: if (r->root_kq > 2) {
97: close(r->root_kq);
98: r->root_kq = 0;
99: }
100:
101: if (r->root_data.iov_base && r->root_data.iov_len) {
102: free(r->root_data.iov_base);
103: r->root_data.iov_base = NULL;
104: r->root_data.iov_len = 0;
105: }
106:
107: return NULL;
108: }
109:
110: /*
111: * sched_hook_cancel() - Default CANCEL hook
112: * @task = current task
113: * @arg = unused
114: * return: <0 errors and 0 ok
115: */
116: void *
117: sched_hook_cancel(void *task, void *arg __unused)
118: {
119: struct sched_IO *io;
120: sched_task_t *t = task;
121: struct kevent chg[1];
1.2 misho 122: struct timespec timeout = { 0, 0 };
1.1 misho 123:
124: if (!t || !t->task_root || !ROOT_DATA(t->task_root) || !ROOT_DATLEN(t->task_root))
125: return (void*) -1;
126: else
127: io = ROOT_DATA(t->task_root);
128:
129: switch (t->task_type) {
130: case taskREAD:
1.2 misho 131: #ifdef __NetBSD__
132: EV_SET(&chg[0], TASK_FD(t), EVFILT_READ, EV_DELETE, 0, 0, (intptr_t) TASK_FD(t));
133: #else
134: EV_SET(&chg[0], TASK_FD(t), EVFILT_READ, EV_DELETE, 0, 0, (void*) TASK_FD(t));
135: #endif
1.1 misho 136: kevent(t->task_root->root_kq, chg, 1, NULL, 0, &timeout);
137: FD_CLR(TASK_FD(t), &io->rfd);
138: break;
139: case taskWRITE:
1.2 misho 140: #ifdef __NetBSD__
141: EV_SET(&chg[0], TASK_FD(t), EVFILT_WRITE, EV_DELETE, 0, 0, (intptr_t) TASK_FD(t));
142: #else
143: EV_SET(&chg[0], TASK_FD(t), EVFILT_WRITE, EV_DELETE, 0, 0, (void*) TASK_FD(t));
144: #endif
1.1 misho 145: kevent(t->task_root->root_kq, chg, 1, NULL, 0, &timeout);
146: FD_CLR(TASK_FD(t), &io->wfd);
147: break;
148: default:
149: break;
150: }
151:
152: return NULL;
153: }
154:
155: /*
156: * sched_hook_read() - Default READ hook
157: * @task = current task
158: * @arg = unused
159: * return: <0 errors and 0 ok
160: */
161: void *
162: sched_hook_read(void *task, void *arg __unused)
163: {
164: struct sched_IO *io;
165: sched_task_t *t = task;
166: struct kevent chg[1];
1.2 misho 167: struct timespec timeout = { 0, 0 };
1.1 misho 168:
169: if (!t || !t->task_root || !ROOT_DATA(t->task_root) || !ROOT_DATLEN(t->task_root))
170: return (void*) -1;
171: else
172: io = ROOT_DATA(t->task_root);
173:
174: if (FD_ISSET(TASK_FD(t), &io->rfd))
175: return NULL;
176: else
177: FD_SET(TASK_FD(t), &io->rfd);
178:
1.2 misho 179: #ifdef __NetBSD__
180: EV_SET(&chg[0], TASK_FD(t), EVFILT_READ, EV_ADD, 0, 0, (intptr_t) TASK_FD(t));
181: #else
182: EV_SET(&chg[0], TASK_FD(t), EVFILT_READ, EV_ADD, 0, 0, (void*) TASK_FD(t));
183: #endif
1.1 misho 184: if (kevent(t->task_root->root_kq, chg, 1, NULL, 0, &timeout) == -1) {
1.2.2.1 ! misho 185: if (t->task_root->root_hooks.hook_exec.exception)
! 186: t->task_root->root_hooks.hook_exec.exception(t->task_root, NULL);
1.1 misho 187: return (void*) -1;
188: }
189:
190: return NULL;
191: }
192:
193: /*
194: * sched_hook_write() - Default WRITE hook
195: * @task = current task
196: * @arg = unused
197: * return: <0 errors and 0 ok
198: */
199: void *
200: sched_hook_write(void *task, void *arg __unused)
201: {
202: struct sched_IO *io;
203: sched_task_t *t = task;
204: struct kevent chg[1];
1.2 misho 205: struct timespec timeout = { 0, 0 };
1.1 misho 206:
207: if (!t || !t->task_root || !ROOT_DATA(t->task_root) || !ROOT_DATLEN(t->task_root))
208: return (void*) -1;
209: else
210: io = ROOT_DATA(t->task_root);
211:
212: if (FD_ISSET(TASK_FD(t), &io->wfd))
213: return NULL;
214: else
215: FD_SET(TASK_FD(t), &io->wfd);
216:
1.2 misho 217: #ifdef __NetBSD__
218: EV_SET(&chg[0], TASK_FD(t), EVFILT_WRITE, EV_ADD, 0, 0, (intptr_t) TASK_FD(t));
219: #else
220: EV_SET(&chg[0], TASK_FD(t), EVFILT_WRITE, EV_ADD, 0, 0, (void*) TASK_FD(t));
221: #endif
1.1 misho 222: if (kevent(t->task_root->root_kq, chg, 1, NULL, 0, &timeout) == -1) {
1.2.2.1 ! misho 223: if (t->task_root->root_hooks.hook_exec.exception)
! 224: t->task_root->root_hooks.hook_exec.exception(t->task_root, NULL);
1.1 misho 225: return (void*) -1;
226: }
227:
228: return NULL;
229: }
230:
231: /*
232: * sched_hook_fetch() - Default FETCH hook
233: * @root = root task
234: * @arg = unused
235: * return: NULL error or !=NULL fetched task
236: */
237: void *
238: sched_hook_fetch(void *root, void *arg __unused)
239: {
240: struct sched_IO *io;
241: sched_root_task_t *r = root;
242: sched_task_t *task;
243: struct timeval now, m, mtmp;
244: struct timespec nw, *timeout;
245: struct kevent evt[1], res[KQ_EVENTS];
246: register int i;
247: int en;
248:
249: if (!r || !ROOT_DATA(r) || !ROOT_DATLEN(r))
250: return NULL;
251:
252: /* get new task by queue priority */
253: retry:
254: while ((task = TAILQ_FIRST(&r->root_event))) {
255: TAILQ_REMOVE(&r->root_event, task, task_node);
256: task->task_type = taskUNUSE;
257: TAILQ_INSERT_TAIL(&r->root_unuse, task, task_node);
258: return task;
259: }
260: while ((task = TAILQ_FIRST(&r->root_ready))) {
261: TAILQ_REMOVE(&r->root_ready, task, task_node);
262: task->task_type = taskUNUSE;
263: TAILQ_INSERT_TAIL(&r->root_unuse, task, task_node);
264: return task;
265: }
266:
267: #ifdef TIMER_WITHOUT_SORT
268: clock_gettime(CLOCK_MONOTONIC, &nw);
269: now.tv_sec = nw.tv_sec;
270: now.tv_usec = nw.tv_nsec / 1000;
271:
272: timerclear(&r->root_wait);
273: TAILQ_FOREACH(task, &r->root_timer, task_node) {
274: if (!timerisset(&r->root_wait))
275: r->root_wait = TASK_TV(task);
276: else if (timercmp(&TASK_TV(task), &r->root_wait, -) < 0)
277: r->root_wait = TASK_TV(task);
278: }
279:
280: if (TAILQ_FIRST(&r->root_timer)) {
281: m = r->root_wait;
282: timersub(&m, &now, &mtmp);
283: r->root_wait = mtmp;
284: } else {
285: /* set wait INFTIM */
286: r->root_wait.tv_sec = r->root_wait.tv_usec = -1;
287: }
288: #else
289: if (!TAILQ_FIRST(&r->root_eventlo) && (task = TAILQ_FIRST(&r->root_timer))) {
290: clock_gettime(CLOCK_MONOTONIC, &nw);
291: now.tv_sec = nw.tv_sec;
292: now.tv_usec = nw.tv_nsec / 1000;
293:
294: m = TASK_TV(task);
295: timersub(&m, &now, &mtmp);
296: r->root_wait = mtmp;
297: } else {
298: /* set wait INFTIM */
299: r->root_wait.tv_sec = r->root_wait.tv_usec = -1;
300: }
301: #endif
302: /* if present member of eventLo, set NOWAIT */
303: if (TAILQ_FIRST(&r->root_eventlo))
304: timerclear(&r->root_wait);
305:
306: if (r->root_wait.tv_sec != -1 && r->root_wait.tv_usec != -1) {
307: nw.tv_sec = r->root_wait.tv_sec;
308: nw.tv_nsec = r->root_wait.tv_usec * 1000;
309: timeout = &nw;
310: } else /* wait INFTIM */
311: timeout = NULL;
312: if ((en = kevent(r->root_kq, NULL, 0, res, KQ_EVENTS, timeout)) == -1) {
1.2.2.1 ! misho 313: if (r->root_hooks.hook_exec.exception)
! 314: if (r->root_hooks.hook_exec.exception(r, NULL))
! 315: return NULL; /* exit from scheduler */
1.2 misho 316: #ifdef NDEBUG
317: /* kevent no exit by error, if non-debug version */
1.1 misho 318: goto retry;
1.2 misho 319: #else
320: /* diagnostic exit from scheduler if kevent error occur */
321: return NULL;
322: #endif
1.1 misho 323: }
324:
1.2 misho 325: nw.tv_sec = nw.tv_nsec = 0;
1.1 misho 326: /* Go and catch the cat into pipes ... */
327: for (i = 0; i < en; i++) {
328: memcpy(evt, &res[i], sizeof evt);
329: evt->flags = EV_DELETE;
330: /* Put read/write task to ready queue */
331: switch (res[i].filter) {
332: case EVFILT_READ:
333: TAILQ_FOREACH(task, &r->root_read, task_node) {
1.2 misho 334: if (TASK_FD(task) != ((int) res[i].udata))
1.1 misho 335: continue;
336: /* remove read handle */
337: io = ROOT_DATA(task->task_root);
338: FD_CLR(TASK_FD(task), &io->rfd);
339:
340: TAILQ_REMOVE(&r->root_read, task, task_node);
1.2.2.1 ! misho 341: if (r->root_hooks.hook_exec.exception && res[i].flags & EV_EOF) {
! 342: if (r->root_hooks.hook_exec.exception(r, (void*) EV_EOF)) {
! 343: task->task_type = taskUNUSE;
! 344: TAILQ_INSERT_TAIL(&r->root_unuse, task, task_node);
! 345: } else {
! 346: task->task_type = taskREADY;
! 347: TAILQ_INSERT_TAIL(&r->root_ready, task, task_node);
! 348: }
! 349: } else {
1.2 misho 350: task->task_type = taskREADY;
351: TAILQ_INSERT_TAIL(&r->root_ready, task, task_node);
1.2.2.1 ! misho 352: }
1.1 misho 353: break;
354: }
355: break;
356: case EVFILT_WRITE:
357: TAILQ_FOREACH(task, &r->root_write, task_node) {
1.2 misho 358: if (TASK_FD(task) != ((int) res[i].udata))
1.1 misho 359: continue;
360: /* remove write handle */
361: io = ROOT_DATA(task->task_root);
362: FD_CLR(TASK_FD(task), &io->wfd);
363:
364: TAILQ_REMOVE(&r->root_write, task, task_node);
1.2.2.1 ! misho 365: if (r->root_hooks.hook_exec.exception && res[i].flags & EV_EOF) {
! 366: if (r->root_hooks.hook_exec.exception(r, (void*) EV_EOF)) {
! 367: task->task_type = taskUNUSE;
! 368: TAILQ_INSERT_TAIL(&r->root_unuse, task, task_node);
! 369: } else {
! 370: task->task_type = taskREADY;
! 371: TAILQ_INSERT_TAIL(&r->root_ready, task, task_node);
! 372: }
! 373: } else {
1.2 misho 374: task->task_type = taskREADY;
375: TAILQ_INSERT_TAIL(&r->root_ready, task, task_node);
1.2.2.1 ! misho 376: }
1.1 misho 377: break;
378: }
379: break;
380: }
381: if (kevent(r->root_kq, evt, 1, NULL, 0, &nw) == -1)
1.2.2.1 ! misho 382: if (r->root_hooks.hook_exec.exception)
! 383: if (r->root_hooks.hook_exec.exception(r, NULL))
! 384: return NULL; /* exit from scheduler */
1.1 misho 385: }
386:
1.2 misho 387: /* timer update & put in ready queue */
1.1 misho 388: clock_gettime(CLOCK_MONOTONIC, &nw);
389: now.tv_sec = nw.tv_sec;
390: now.tv_usec = nw.tv_nsec / 1000;
391:
392: TAILQ_FOREACH(task, &r->root_timer, task_node)
393: if (timercmp(&now, &TASK_TV(task), -) >= 0) {
394: TAILQ_REMOVE(&r->root_timer, task, task_node);
395: task->task_type = taskREADY;
396: TAILQ_INSERT_TAIL(&r->root_ready, task, task_node);
397: }
398:
399: /* put eventlo priority task to ready queue, if there is no ready task or
400: reach max missed fetch-rotate */
401: if ((task = TAILQ_FIRST(&r->root_eventlo))) {
402: if (!TAILQ_FIRST(&r->root_ready) || r->root_eventlo_miss > MAX_EVENTLO_MISS) {
403: r->root_eventlo_miss = 0;
404:
405: TAILQ_REMOVE(&r->root_eventlo, task, task_node);
406: task->task_type = taskREADY;
407: TAILQ_INSERT_TAIL(&r->root_ready, task, task_node);
408: } else
409: r->root_eventlo_miss++;
410: } else
411: r->root_eventlo_miss = 0;
412:
413: /* OK, lets get ready task !!! */
414: if (!(task = TAILQ_FIRST(&r->root_ready)))
415: goto retry;
416: TAILQ_REMOVE(&r->root_ready, task, task_node);
417: task->task_type = taskUNUSE;
418: TAILQ_INSERT_TAIL(&r->root_unuse, task, task_node);
419: return task;
420: }
1.2.2.1 ! misho 421:
! 422: /*
! 423: * sched_hook_exception() - Default EXCEPTION hook
! 424: * @root = root task
! 425: * @arg = may be EV_EOF
! 426: * return: <0 errors and 0 ok
! 427: */
! 428: void *
! 429: sched_hook_exception(void *root, void *arg)
! 430: {
! 431: sched_root_task_t *r = root;
! 432:
! 433: if (!r || !ROOT_DATA(r) || !ROOT_DATLEN(r))
! 434: return NULL;
! 435:
! 436: if (arg) {
! 437: if (arg == (void*) EV_EOF)
! 438: return NULL;
! 439: return (void*) -1; /* raise error */
! 440: } else
! 441: LOGERR;
! 442:
! 443: if (errno == EINTR)
! 444: return (void*) -1; /* raise error */
! 445:
! 446: return NULL;
! 447: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>