Annotation of libaitsched/src/hooks.c, revision 1.1.1.1.2.3
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.1.1.1.2.3! misho 6: * $Id: hooks.c,v 1.1.1.1.2.2 2011/08/11 12:56:53 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.1.1.1.2.1 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:
131: if (FD_ISSET(TASK_FD(t), &io->wfd))
1.1.1.1.2.3! misho 132: #ifdef __NetBSD__
1.1.1.1.2.2 misho 133: EV_SET(&chg[0], TASK_FD(t), EVFILT_WRITE, EV_ADD, 0, 0, (intptr_t) &TASK_FD(t));
1.1.1.1.2.3! misho 134: #else
! 135: EV_SET(&chg[0], TASK_FD(t), EVFILT_WRITE, EV_ADD, 0, 0, &TASK_FD(t));
! 136: #endif
1.1 misho 137: else
1.1.1.1.2.3! misho 138: #ifdef __NetBSD__
1.1.1.1.2.2 misho 139: EV_SET(&chg[0], TASK_FD(t), EVFILT_WRITE, EV_DELETE, 0, 0, (intptr_t) &TASK_FD(t));
1.1.1.1.2.3! misho 140: #else
! 141: EV_SET(&chg[0], TASK_FD(t), EVFILT_WRITE, EV_DELETE, 0, 0, &TASK_FD(t));
! 142: #endif
1.1 misho 143: kevent(t->task_root->root_kq, chg, 1, NULL, 0, &timeout);
144:
145: FD_CLR(TASK_FD(t), &io->rfd);
146: break;
147: case taskWRITE:
148: if (FD_ISSET(TASK_FD(t), &io->rfd))
1.1.1.1.2.3! misho 149: #ifdef __NetBSD__
1.1.1.1.2.2 misho 150: EV_SET(&chg[0], TASK_FD(t), EVFILT_READ, EV_ADD, 0, 0, (intptr_t) &TASK_FD(t));
1.1.1.1.2.3! misho 151: #else
! 152: EV_SET(&chg[0], TASK_FD(t), EVFILT_READ, EV_ADD, 0, 0, &TASK_FD(t));
! 153: #endif
1.1 misho 154: else
1.1.1.1.2.3! misho 155: #ifdef __NetBSD__
1.1.1.1.2.2 misho 156: EV_SET(&chg[0], TASK_FD(t), EVFILT_READ, EV_DELETE, 0, 0, (intptr_t) &TASK_FD(t));
1.1.1.1.2.3! misho 157: #else
! 158: EV_SET(&chg[0], TASK_FD(t), EVFILT_READ, EV_DELETE, 0, 0, &TASK_FD(t));
! 159: #endif
1.1 misho 160: kevent(t->task_root->root_kq, chg, 1, NULL, 0, &timeout);
161:
162: FD_CLR(TASK_FD(t), &io->wfd);
163: break;
164: default:
165: break;
166: }
167:
168: return NULL;
169: }
170:
171: /*
172: * sched_hook_read() - Default READ hook
173: * @task = current task
174: * @arg = unused
175: * return: <0 errors and 0 ok
176: */
177: void *
178: sched_hook_read(void *task, void *arg __unused)
179: {
180: struct sched_IO *io;
181: sched_task_t *t = task;
182: struct kevent chg[1];
1.1.1.1.2.1 misho 183: struct timespec timeout = { 0, 0 };
1.1 misho 184:
185: if (!t || !t->task_root || !ROOT_DATA(t->task_root) || !ROOT_DATLEN(t->task_root))
186: return (void*) -1;
187: else
188: io = ROOT_DATA(t->task_root);
189:
190: if (FD_ISSET(TASK_FD(t), &io->rfd))
191: return NULL;
192: else
193: FD_SET(TASK_FD(t), &io->rfd);
194:
1.1.1.1.2.3! misho 195: #ifdef __NetBSD__
1.1.1.1.2.2 misho 196: EV_SET(&chg[0], TASK_FD(t), EVFILT_READ, EV_ADD, 0, 0, (intptr_t) &TASK_FD(t));
1.1.1.1.2.3! misho 197: #else
! 198: EV_SET(&chg[0], TASK_FD(t), EVFILT_READ, EV_ADD, 0, 0, &TASK_FD(t));
! 199: #endif
1.1 misho 200: if (kevent(t->task_root->root_kq, chg, 1, NULL, 0, &timeout) == -1) {
201: LOGERR;
202: return (void*) -1;
203: }
204:
205: return NULL;
206: }
207:
208: /*
209: * sched_hook_write() - Default WRITE hook
210: * @task = current task
211: * @arg = unused
212: * return: <0 errors and 0 ok
213: */
214: void *
215: sched_hook_write(void *task, void *arg __unused)
216: {
217: struct sched_IO *io;
218: sched_task_t *t = task;
219: struct kevent chg[1];
1.1.1.1.2.1 misho 220: struct timespec timeout = { 0, 0 };
1.1 misho 221:
222: if (!t || !t->task_root || !ROOT_DATA(t->task_root) || !ROOT_DATLEN(t->task_root))
223: return (void*) -1;
224: else
225: io = ROOT_DATA(t->task_root);
226:
227: if (FD_ISSET(TASK_FD(t), &io->wfd))
228: return NULL;
229: else
230: FD_SET(TASK_FD(t), &io->wfd);
231:
1.1.1.1.2.3! misho 232: #ifdef __NetBSD__
1.1.1.1.2.2 misho 233: EV_SET(&chg[0], TASK_FD(t), EVFILT_WRITE, EV_ADD, 0, 0, (intptr_t) &TASK_FD(t));
1.1.1.1.2.3! misho 234: #else
! 235: EV_SET(&chg[0], TASK_FD(t), EVFILT_WRITE, EV_ADD, 0, 0, &TASK_FD(t));
! 236: #endif
1.1 misho 237: if (kevent(t->task_root->root_kq, chg, 1, NULL, 0, &timeout) == -1) {
238: LOGERR;
239: return (void*) -1;
240: }
241:
242: return NULL;
243: }
244:
245: /*
246: * sched_hook_fetch() - Default FETCH hook
247: * @root = root task
248: * @arg = unused
249: * return: NULL error or !=NULL fetched task
250: */
251: void *
252: sched_hook_fetch(void *root, void *arg __unused)
253: {
254: struct sched_IO *io;
255: sched_root_task_t *r = root;
256: sched_task_t *task;
257: struct timeval now, m, mtmp;
258: struct timespec nw, *timeout;
259: struct kevent evt[1], res[KQ_EVENTS];
260: register int i;
261: int en;
262:
263: if (!r || !ROOT_DATA(r) || !ROOT_DATLEN(r))
264: return NULL;
265:
266: /* get new task by queue priority */
267: retry:
268: while ((task = TAILQ_FIRST(&r->root_event))) {
269: TAILQ_REMOVE(&r->root_event, task, task_node);
270: task->task_type = taskUNUSE;
271: TAILQ_INSERT_TAIL(&r->root_unuse, task, task_node);
272: return task;
273: }
274: while ((task = TAILQ_FIRST(&r->root_ready))) {
275: TAILQ_REMOVE(&r->root_ready, task, task_node);
276: task->task_type = taskUNUSE;
277: TAILQ_INSERT_TAIL(&r->root_unuse, task, task_node);
278: return task;
279: }
280:
281: #ifdef TIMER_WITHOUT_SORT
282: clock_gettime(CLOCK_MONOTONIC, &nw);
283: now.tv_sec = nw.tv_sec;
284: now.tv_usec = nw.tv_nsec / 1000;
285:
286: timerclear(&r->root_wait);
287: TAILQ_FOREACH(task, &r->root_timer, task_node) {
288: if (!timerisset(&r->root_wait))
289: r->root_wait = TASK_TV(task);
290: else if (timercmp(&TASK_TV(task), &r->root_wait, -) < 0)
291: r->root_wait = TASK_TV(task);
292: }
293:
294: if (TAILQ_FIRST(&r->root_timer)) {
295: m = r->root_wait;
296: timersub(&m, &now, &mtmp);
297: r->root_wait = mtmp;
298: } else {
299: /* set wait INFTIM */
300: r->root_wait.tv_sec = r->root_wait.tv_usec = -1;
301: }
302: #else
303: if (!TAILQ_FIRST(&r->root_eventlo) && (task = TAILQ_FIRST(&r->root_timer))) {
304: clock_gettime(CLOCK_MONOTONIC, &nw);
305: now.tv_sec = nw.tv_sec;
306: now.tv_usec = nw.tv_nsec / 1000;
307:
308: m = TASK_TV(task);
309: timersub(&m, &now, &mtmp);
310: r->root_wait = mtmp;
311: } else {
312: /* set wait INFTIM */
313: r->root_wait.tv_sec = r->root_wait.tv_usec = -1;
314: }
315: #endif
316: /* if present member of eventLo, set NOWAIT */
317: if (TAILQ_FIRST(&r->root_eventlo))
318: timerclear(&r->root_wait);
319:
320: if (r->root_wait.tv_sec != -1 && r->root_wait.tv_usec != -1) {
321: nw.tv_sec = r->root_wait.tv_sec;
322: nw.tv_nsec = r->root_wait.tv_usec * 1000;
323: timeout = &nw;
324: } else /* wait INFTIM */
325: timeout = NULL;
326: if ((en = kevent(r->root_kq, NULL, 0, res, KQ_EVENTS, timeout)) == -1) {
327: LOGERR;
328: goto retry;
329: }
330:
1.1.1.1.2.1 misho 331: nw.tv_sec = nw.tv_nsec = 0;
1.1 misho 332: /* Go and catch the cat into pipes ... */
333: for (i = 0; i < en; i++) {
334: memcpy(evt, &res[i], sizeof evt);
335: evt->flags = EV_DELETE;
336: /* Put read/write task to ready queue */
337: switch (res[i].filter) {
338: case EVFILT_READ:
339: TAILQ_FOREACH(task, &r->root_read, task_node) {
340: if (TASK_FD(task) != *((int*) res[i].udata))
341: continue;
342: /* remove read handle */
343: io = ROOT_DATA(task->task_root);
344: FD_CLR(TASK_FD(task), &io->rfd);
345:
346: TAILQ_REMOVE(&r->root_read, task, task_node);
347: task->task_type = taskREADY;
348: TAILQ_INSERT_TAIL(&r->root_ready, task, task_node);
349: break;
350: }
351: break;
352: case EVFILT_WRITE:
353: TAILQ_FOREACH(task, &r->root_write, task_node) {
354: if (TASK_FD(task) != *((int*) res[i].udata))
355: continue;
356: /* remove write handle */
357: io = ROOT_DATA(task->task_root);
358: FD_CLR(TASK_FD(task), &io->wfd);
359:
360: TAILQ_REMOVE(&r->root_write, task, task_node);
361: task->task_type = taskREADY;
362: TAILQ_INSERT_TAIL(&r->root_ready, task, task_node);
363: break;
364: }
365: break;
366: }
367:
368: if (kevent(r->root_kq, evt, 1, NULL, 0, &nw) == -1)
369: LOGERR;
370: }
371:
372: /* timer update */
373: clock_gettime(CLOCK_MONOTONIC, &nw);
374: now.tv_sec = nw.tv_sec;
375: now.tv_usec = nw.tv_nsec / 1000;
376:
377: TAILQ_FOREACH(task, &r->root_timer, task_node)
378: if (timercmp(&now, &TASK_TV(task), -) >= 0) {
379: TAILQ_REMOVE(&r->root_timer, task, task_node);
380: task->task_type = taskREADY;
381: TAILQ_INSERT_TAIL(&r->root_ready, task, task_node);
382: }
383:
384: /* put eventlo priority task to ready queue, if there is no ready task or
385: reach max missed fetch-rotate */
386: if ((task = TAILQ_FIRST(&r->root_eventlo))) {
387: if (!TAILQ_FIRST(&r->root_ready) || r->root_eventlo_miss > MAX_EVENTLO_MISS) {
388: r->root_eventlo_miss = 0;
389:
390: TAILQ_REMOVE(&r->root_eventlo, task, task_node);
391: task->task_type = taskREADY;
392: TAILQ_INSERT_TAIL(&r->root_ready, task, task_node);
393: } else
394: r->root_eventlo_miss++;
395: } else
396: r->root_eventlo_miss = 0;
397:
398: /* OK, lets get ready task !!! */
399: if (!(task = TAILQ_FIRST(&r->root_ready)))
400: goto retry;
401: TAILQ_REMOVE(&r->root_ready, task, task_node);
402: task->task_type = taskUNUSE;
403: TAILQ_INSERT_TAIL(&r->root_unuse, task, task_node);
404: return task;
405: }
406:
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>