Annotation of libaitsched/src/hooks.c, revision 1.5.2.2
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.5.2.2 ! misho 6: * $Id: hooks.c,v 1.5.2.1 2012/04/24 13:29:28 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:
1.5 misho 15: Copyright 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012
1.1 misho 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
1.5 misho 52: *
1.1 misho 53: * @root = root task
1.5.2.2 ! misho 54: * @arg = unused
1.1 misho 55: * return: <0 errors and 0 ok
56: */
57: void *
1.5.2.2 ! misho 58: sched_hook_init(void *root, void *arg __unused)
1.1 misho 59: {
60: sched_root_task_t *r = root;
61:
1.5.2.2 ! misho 62: if (!r)
1.1 misho 63: return (void*) -1;
64:
65: r->root_kq = kqueue();
66: if (r->root_kq == -1) {
67: LOGERR;
68: return (void*) -1;
69: }
70:
71: return NULL;
72: }
73:
74: /*
75: * sched_hook_fini() - Default FINI hook
1.5 misho 76: *
1.1 misho 77: * @root = root task
78: * @arg = unused
79: * return: <0 errors and 0 ok
80: */
81: void *
82: sched_hook_fini(void *root, void *arg __unused)
83: {
84: sched_root_task_t *r = root;
85:
86: if (!r)
87: return (void*) -1;
88:
89: if (r->root_kq > 2) {
90: close(r->root_kq);
91: r->root_kq = 0;
92: }
93:
94: return NULL;
95: }
96:
97: /*
98: * sched_hook_cancel() - Default CANCEL hook
1.5 misho 99: *
1.1 misho 100: * @task = current task
101: * @arg = unused
102: * return: <0 errors and 0 ok
103: */
104: void *
105: sched_hook_cancel(void *task, void *arg __unused)
106: {
107: sched_task_t *t = task;
108: struct kevent chg[1];
1.2 misho 109: struct timespec timeout = { 0, 0 };
1.1 misho 110:
1.5.2.2 ! misho 111: if (!t || !TASK_ROOT(t))
1.1 misho 112: return (void*) -1;
113:
1.4 misho 114: switch (TASK_TYPE(t)) {
1.1 misho 115: case taskREAD:
1.2 misho 116: #ifdef __NetBSD__
117: EV_SET(&chg[0], TASK_FD(t), EVFILT_READ, EV_DELETE, 0, 0, (intptr_t) TASK_FD(t));
118: #else
119: EV_SET(&chg[0], TASK_FD(t), EVFILT_READ, EV_DELETE, 0, 0, (void*) TASK_FD(t));
120: #endif
1.4 misho 121: kevent(TASK_ROOT(t)->root_kq, chg, 1, NULL, 0, &timeout);
1.1 misho 122: break;
123: case taskWRITE:
1.2 misho 124: #ifdef __NetBSD__
125: EV_SET(&chg[0], TASK_FD(t), EVFILT_WRITE, EV_DELETE, 0, 0, (intptr_t) TASK_FD(t));
126: #else
127: EV_SET(&chg[0], TASK_FD(t), EVFILT_WRITE, EV_DELETE, 0, 0, (void*) TASK_FD(t));
128: #endif
1.4 misho 129: kevent(TASK_ROOT(t)->root_kq, chg, 1, NULL, 0, &timeout);
1.1 misho 130: break;
131: default:
132: break;
133: }
134:
135: return NULL;
136: }
137:
138: /*
139: * sched_hook_read() - Default READ hook
1.5 misho 140: *
1.1 misho 141: * @task = current task
142: * @arg = unused
143: * return: <0 errors and 0 ok
144: */
145: void *
146: sched_hook_read(void *task, void *arg __unused)
147: {
148: sched_task_t *t = task;
149: struct kevent chg[1];
1.2 misho 150: struct timespec timeout = { 0, 0 };
1.1 misho 151:
1.5.2.2 ! misho 152: if (!t || !TASK_ROOT(t))
1.1 misho 153: return (void*) -1;
154:
1.2 misho 155: #ifdef __NetBSD__
156: EV_SET(&chg[0], TASK_FD(t), EVFILT_READ, EV_ADD, 0, 0, (intptr_t) TASK_FD(t));
157: #else
158: EV_SET(&chg[0], TASK_FD(t), EVFILT_READ, EV_ADD, 0, 0, (void*) TASK_FD(t));
159: #endif
1.4 misho 160: if (kevent(TASK_ROOT(t)->root_kq, chg, 1, NULL, 0, &timeout) == -1) {
161: if (TASK_ROOT(t)->root_hooks.hook_exec.exception)
162: TASK_ROOT(t)->root_hooks.hook_exec.exception(TASK_ROOT(t), NULL);
1.3 misho 163: else
164: LOGERR;
1.1 misho 165: return (void*) -1;
166: }
167:
168: return NULL;
169: }
170:
171: /*
172: * sched_hook_write() - Default WRITE hook
1.5 misho 173: *
1.1 misho 174: * @task = current task
175: * @arg = unused
176: * return: <0 errors and 0 ok
177: */
178: void *
179: sched_hook_write(void *task, void *arg __unused)
180: {
181: sched_task_t *t = task;
182: struct kevent chg[1];
1.2 misho 183: struct timespec timeout = { 0, 0 };
1.1 misho 184:
1.5.2.2 ! misho 185: if (!t || !TASK_ROOT(t))
1.1 misho 186: return (void*) -1;
187:
1.2 misho 188: #ifdef __NetBSD__
189: EV_SET(&chg[0], TASK_FD(t), EVFILT_WRITE, EV_ADD, 0, 0, (intptr_t) TASK_FD(t));
190: #else
191: EV_SET(&chg[0], TASK_FD(t), EVFILT_WRITE, EV_ADD, 0, 0, (void*) TASK_FD(t));
192: #endif
1.4 misho 193: if (kevent(TASK_ROOT(t)->root_kq, chg, 1, NULL, 0, &timeout) == -1) {
194: if (TASK_ROOT(t)->root_hooks.hook_exec.exception)
195: TASK_ROOT(t)->root_hooks.hook_exec.exception(TASK_ROOT(t), NULL);
1.3 misho 196: else
197: LOGERR;
1.1 misho 198: return (void*) -1;
199: }
200:
201: return NULL;
202: }
203:
204: /*
205: * sched_hook_fetch() - Default FETCH hook
1.5 misho 206: *
1.1 misho 207: * @root = root task
208: * @arg = unused
209: * return: NULL error or !=NULL fetched task
210: */
211: void *
212: sched_hook_fetch(void *root, void *arg __unused)
213: {
214: sched_root_task_t *r = root;
215: sched_task_t *task;
1.4 misho 216: struct timespec now, m, mtmp;
217: struct timespec *timeout;
1.1 misho 218: struct kevent evt[1], res[KQ_EVENTS];
219: register int i;
220: int en;
221:
1.5.2.2 ! misho 222: if (!r)
1.1 misho 223: return NULL;
224:
225: /* get new task by queue priority */
226: retry:
227: while ((task = TAILQ_FIRST(&r->root_event))) {
1.4 misho 228: #ifdef HAVE_LIBPTHREAD
229: pthread_mutex_lock(&r->root_mtx[taskEVENT]);
230: #endif
1.1 misho 231: TAILQ_REMOVE(&r->root_event, task, task_node);
1.4 misho 232: #ifdef HAVE_LIBPTHREAD
233: pthread_mutex_unlock(&r->root_mtx[taskEVENT]);
234: #endif
1.1 misho 235: task->task_type = taskUNUSE;
1.4 misho 236: #ifdef HAVE_LIBPTHREAD
237: pthread_mutex_lock(&r->root_mtx[taskUNUSE]);
238: #endif
1.1 misho 239: TAILQ_INSERT_TAIL(&r->root_unuse, task, task_node);
1.4 misho 240: #ifdef HAVE_LIBPTHREAD
241: pthread_mutex_unlock(&r->root_mtx[taskUNUSE]);
242: #endif
1.1 misho 243: return task;
244: }
245: while ((task = TAILQ_FIRST(&r->root_ready))) {
1.4 misho 246: #ifdef HAVE_LIBPTHREAD
247: pthread_mutex_lock(&r->root_mtx[taskREADY]);
248: #endif
1.1 misho 249: TAILQ_REMOVE(&r->root_ready, task, task_node);
1.4 misho 250: #ifdef HAVE_LIBPTHREAD
251: pthread_mutex_unlock(&r->root_mtx[taskREADY]);
252: #endif
1.1 misho 253: task->task_type = taskUNUSE;
1.4 misho 254: #ifdef HAVE_LIBPTHREAD
255: pthread_mutex_lock(&r->root_mtx[taskUNUSE]);
256: #endif
1.1 misho 257: TAILQ_INSERT_TAIL(&r->root_unuse, task, task_node);
1.4 misho 258: #ifdef HAVE_LIBPTHREAD
259: pthread_mutex_unlock(&r->root_mtx[taskUNUSE]);
260: #endif
1.1 misho 261: return task;
262: }
263:
264: #ifdef TIMER_WITHOUT_SORT
1.4 misho 265: clock_gettime(CLOCK_MONOTONIC, &now);
1.1 misho 266:
1.4 misho 267: sched_timespecclear(&r->root_wait);
1.1 misho 268: TAILQ_FOREACH(task, &r->root_timer, task_node) {
1.4 misho 269: if (!sched_timespecisset(&r->root_wait))
270: r->root_wait = TASK_TS(task);
271: else if (sched_timespeccmp(&TASK_TS(task), &r->root_wait, -) < 0)
272: r->root_wait = TASK_TS(task);
1.1 misho 273: }
274:
275: if (TAILQ_FIRST(&r->root_timer)) {
276: m = r->root_wait;
1.4 misho 277: sched_timespecsub(&m, &now, &mtmp);
1.1 misho 278: r->root_wait = mtmp;
279: } else {
280: /* set wait INFTIM */
1.4 misho 281: sched_timespecinf(&r->root_wait);
1.1 misho 282: }
283: #else
284: if (!TAILQ_FIRST(&r->root_eventlo) && (task = TAILQ_FIRST(&r->root_timer))) {
1.4 misho 285: clock_gettime(CLOCK_MONOTONIC, &now);
1.1 misho 286:
1.4 misho 287: m = TASK_TS(task);
288: sched_timespecsub(&m, &now, &mtmp);
1.1 misho 289: r->root_wait = mtmp;
290: } else {
291: /* set wait INFTIM */
1.4 misho 292: sched_timespecinf(&r->root_wait);
1.1 misho 293: }
294: #endif
295: /* if present member of eventLo, set NOWAIT */
296: if (TAILQ_FIRST(&r->root_eventlo))
1.4 misho 297: sched_timespecclear(&r->root_wait);
1.1 misho 298:
1.4 misho 299: if (r->root_wait.tv_sec != -1 && r->root_wait.tv_nsec != -1)
300: timeout = &r->root_wait;
301: else if (sched_timespecisinf(&r->root_poll))
1.1 misho 302: timeout = NULL;
1.4 misho 303: else
304: timeout = &r->root_poll;
1.1 misho 305: if ((en = kevent(r->root_kq, NULL, 0, res, KQ_EVENTS, timeout)) == -1) {
1.3 misho 306: if (r->root_hooks.hook_exec.exception) {
307: if (r->root_hooks.hook_exec.exception(r, NULL))
308: return NULL;
309: } else
310: LOGERR;
1.2 misho 311: #ifdef NDEBUG
312: /* kevent no exit by error, if non-debug version */
1.1 misho 313: goto retry;
1.2 misho 314: #else
315: /* diagnostic exit from scheduler if kevent error occur */
316: return NULL;
317: #endif
1.1 misho 318: }
319:
1.4 misho 320: now.tv_sec = now.tv_nsec = 0;
1.1 misho 321: /* Go and catch the cat into pipes ... */
322: for (i = 0; i < en; i++) {
323: memcpy(evt, &res[i], sizeof evt);
324: evt->flags = EV_DELETE;
325: /* Put read/write task to ready queue */
326: switch (res[i].filter) {
327: case EVFILT_READ:
328: TAILQ_FOREACH(task, &r->root_read, task_node) {
1.3 misho 329: if (TASK_FD(task) != ((intptr_t) res[i].udata))
1.1 misho 330: continue;
331: /* remove read handle */
1.4 misho 332: #ifdef HAVE_LIBPTHREAD
333: pthread_mutex_lock(&r->root_mtx[taskREAD]);
334: #endif
1.1 misho 335: TAILQ_REMOVE(&r->root_read, task, task_node);
1.4 misho 336: #ifdef HAVE_LIBPTHREAD
337: pthread_mutex_unlock(&r->root_mtx[taskREAD]);
338: #endif
1.3 misho 339: if (r->root_hooks.hook_exec.exception && res[i].flags & EV_EOF) {
340: if (r->root_hooks.hook_exec.exception(r, (void*) EV_EOF)) {
341: task->task_type = taskUNUSE;
1.4 misho 342: #ifdef HAVE_LIBPTHREAD
343: pthread_mutex_lock(&r->root_mtx[taskUNUSE]);
344: #endif
1.3 misho 345: TAILQ_INSERT_TAIL(&r->root_unuse, task, task_node);
1.4 misho 346: #ifdef HAVE_LIBPTHREAD
347: pthread_mutex_unlock(&r->root_mtx[taskUNUSE]);
348: #endif
1.3 misho 349: } else {
350: task->task_type = taskREADY;
1.4 misho 351: #ifdef HAVE_LIBPTHREAD
352: pthread_mutex_lock(&r->root_mtx[taskREADY]);
353: #endif
1.3 misho 354: TAILQ_INSERT_TAIL(&r->root_ready, task, task_node);
1.4 misho 355: #ifdef HAVE_LIBPTHREAD
356: pthread_mutex_unlock(&r->root_mtx[taskREADY]);
357: #endif
1.3 misho 358: }
359: } else {
1.2 misho 360: task->task_type = taskREADY;
1.4 misho 361: #ifdef HAVE_LIBPTHREAD
362: pthread_mutex_lock(&r->root_mtx[taskREADY]);
363: #endif
1.2 misho 364: TAILQ_INSERT_TAIL(&r->root_ready, task, task_node);
1.4 misho 365: #ifdef HAVE_LIBPTHREAD
366: pthread_mutex_unlock(&r->root_mtx[taskREADY]);
367: #endif
1.3 misho 368: }
1.1 misho 369: break;
370: }
371: break;
372: case EVFILT_WRITE:
373: TAILQ_FOREACH(task, &r->root_write, task_node) {
1.3 misho 374: if (TASK_FD(task) != ((intptr_t) res[i].udata))
1.1 misho 375: continue;
376: /* remove write handle */
1.4 misho 377: #ifdef HAVE_LIBPTHREAD
378: pthread_mutex_lock(&r->root_mtx[taskWRITE]);
379: #endif
1.1 misho 380: TAILQ_REMOVE(&r->root_write, task, task_node);
1.4 misho 381: #ifdef HAVE_LIBPTHREAD
382: pthread_mutex_unlock(&r->root_mtx[taskWRITE]);
383: #endif
1.3 misho 384: if (r->root_hooks.hook_exec.exception && res[i].flags & EV_EOF) {
385: if (r->root_hooks.hook_exec.exception(r, (void*) EV_EOF)) {
386: task->task_type = taskUNUSE;
1.4 misho 387: #ifdef HAVE_LIBPTHREAD
388: pthread_mutex_lock(&r->root_mtx[taskUNUSE]);
389: #endif
1.3 misho 390: TAILQ_INSERT_TAIL(&r->root_unuse, task, task_node);
1.4 misho 391: #ifdef HAVE_LIBPTHREAD
392: pthread_mutex_unlock(&r->root_mtx[taskUNUSE]);
393: #endif
1.3 misho 394: } else {
395: task->task_type = taskREADY;
1.4 misho 396: #ifdef HAVE_LIBPTHREAD
397: pthread_mutex_lock(&r->root_mtx[taskREADY]);
398: #endif
1.3 misho 399: TAILQ_INSERT_TAIL(&r->root_ready, task, task_node);
1.4 misho 400: #ifdef HAVE_LIBPTHREAD
401: pthread_mutex_unlock(&r->root_mtx[taskREADY]);
402: #endif
1.3 misho 403: }
404: } else {
1.2 misho 405: task->task_type = taskREADY;
1.4 misho 406: #ifdef HAVE_LIBPTHREAD
407: pthread_mutex_lock(&r->root_mtx[taskREADY]);
408: #endif
1.2 misho 409: TAILQ_INSERT_TAIL(&r->root_ready, task, task_node);
1.4 misho 410: #ifdef HAVE_LIBPTHREAD
411: pthread_mutex_unlock(&r->root_mtx[taskREADY]);
412: #endif
1.3 misho 413: }
1.1 misho 414: break;
415: }
416: break;
417: }
1.4 misho 418: if (kevent(r->root_kq, evt, 1, NULL, 0, &now) == -1) {
1.3 misho 419: if (r->root_hooks.hook_exec.exception) {
420: if (r->root_hooks.hook_exec.exception(r, NULL))
421: return NULL;
422: } else
423: LOGERR;
424: }
1.1 misho 425: }
426:
1.2 misho 427: /* timer update & put in ready queue */
1.4 misho 428: clock_gettime(CLOCK_MONOTONIC, &now);
1.1 misho 429:
430: TAILQ_FOREACH(task, &r->root_timer, task_node)
1.4 misho 431: if (sched_timespeccmp(&now, &TASK_TS(task), -) >= 0) {
432: #ifdef HAVE_LIBPTHREAD
433: pthread_mutex_lock(&r->root_mtx[taskTIMER]);
434: #endif
1.1 misho 435: TAILQ_REMOVE(&r->root_timer, task, task_node);
1.4 misho 436: #ifdef HAVE_LIBPTHREAD
437: pthread_mutex_unlock(&r->root_mtx[taskTIMER]);
438: #endif
1.1 misho 439: task->task_type = taskREADY;
1.4 misho 440: #ifdef HAVE_LIBPTHREAD
441: pthread_mutex_lock(&r->root_mtx[taskREADY]);
442: #endif
1.1 misho 443: TAILQ_INSERT_TAIL(&r->root_ready, task, task_node);
1.4 misho 444: #ifdef HAVE_LIBPTHREAD
445: pthread_mutex_unlock(&r->root_mtx[taskREADY]);
446: #endif
1.1 misho 447: }
448:
449: /* put eventlo priority task to ready queue, if there is no ready task or
450: reach max missed fetch-rotate */
451: if ((task = TAILQ_FIRST(&r->root_eventlo))) {
452: if (!TAILQ_FIRST(&r->root_ready) || r->root_eventlo_miss > MAX_EVENTLO_MISS) {
453: r->root_eventlo_miss = 0;
454:
1.4 misho 455: #ifdef HAVE_LIBPTHREAD
456: pthread_mutex_lock(&r->root_mtx[taskEVENTLO]);
457: #endif
1.1 misho 458: TAILQ_REMOVE(&r->root_eventlo, task, task_node);
1.4 misho 459: #ifdef HAVE_LIBPTHREAD
460: pthread_mutex_unlock(&r->root_mtx[taskEVENTLO]);
461: #endif
1.1 misho 462: task->task_type = taskREADY;
1.4 misho 463: #ifdef HAVE_LIBPTHREAD
464: pthread_mutex_lock(&r->root_mtx[taskREADY]);
465: #endif
1.1 misho 466: TAILQ_INSERT_TAIL(&r->root_ready, task, task_node);
1.4 misho 467: #ifdef HAVE_LIBPTHREAD
468: pthread_mutex_unlock(&r->root_mtx[taskREADY]);
469: #endif
1.1 misho 470: } else
471: r->root_eventlo_miss++;
472: } else
473: r->root_eventlo_miss = 0;
474:
475: /* OK, lets get ready task !!! */
1.5.2.1 misho 476: task = TAILQ_FIRST(&r->root_ready);
477: if (!(task))
478: return NULL;
479:
1.4 misho 480: #ifdef HAVE_LIBPTHREAD
481: pthread_mutex_lock(&r->root_mtx[taskREADY]);
482: #endif
1.1 misho 483: TAILQ_REMOVE(&r->root_ready, task, task_node);
1.4 misho 484: #ifdef HAVE_LIBPTHREAD
485: pthread_mutex_unlock(&r->root_mtx[taskREADY]);
486: #endif
1.1 misho 487: task->task_type = taskUNUSE;
1.4 misho 488: #ifdef HAVE_LIBPTHREAD
489: pthread_mutex_lock(&r->root_mtx[taskUNUSE]);
490: #endif
1.1 misho 491: TAILQ_INSERT_TAIL(&r->root_unuse, task, task_node);
1.4 misho 492: #ifdef HAVE_LIBPTHREAD
493: pthread_mutex_unlock(&r->root_mtx[taskUNUSE]);
494: #endif
1.1 misho 495: return task;
496: }
1.3 misho 497:
498: /*
499: * sched_hook_exception() - Default EXCEPTION hook
1.5 misho 500: *
1.3 misho 501: * @root = root task
502: * @arg = custom handling: if arg == EV_EOF or other value; default: arg == NULL log errno
503: * return: <0 errors and 0 ok
504: */
505: void *
506: sched_hook_exception(void *root, void *arg)
507: {
508: sched_root_task_t *r = root;
509:
1.5.2.2 ! misho 510: if (!r)
1.3 misho 511: return NULL;
512:
513: /* custom exception handling ... */
514: if (arg) {
515: if (arg == (void*) EV_EOF)
516: return NULL;
517: return (void*) -1; /* raise scheduler error!!! */
518: }
519:
520: /* if error hook exists */
521: if (r->root_hooks.hook_root.error)
522: return (r->root_hooks.hook_root.error(root, (void*) ((intptr_t) errno)));
523:
524: /* default case! */
525: LOGERR;
526: return NULL;
527: }
1.5 misho 528:
529: /*
530: * sched_hook_condition() - Default CONDITION hook
531: *
532: * @root = root task
533: * @arg = killState from schedRun()
534: * return: NULL kill scheduler loop or !=NULL ok
535: */
536: void *
537: sched_hook_condition(void *root, void *arg)
538: {
539: sched_root_task_t *r = root;
540:
1.5.2.2 ! misho 541: if (!r)
1.5 misho 542: return NULL;
543:
544: return (void*) (r->root_cond - *(intptr_t*) arg);
545: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>