Annotation of libaitsched/src/tasks.c, revision 1.25.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.25.2.2! misho 6: * $Id: tasks.c,v 1.25.2.1 2015/07/02 22:38: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.25.2.2! misho 15: Copyright 2004 - 2015
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:
48:
1.13 misho 49: /*
50: * sched_useTask() - Get and init new task
51: *
52: * @root = root task
53: * return: NULL error or !=NULL prepared task
54: */
1.16 misho 55: sched_task_t *
1.13 misho 56: sched_useTask(sched_root_task_t * __restrict root)
1.4 misho 57: {
1.7 misho 58: sched_task_t *task, *tmp;
1.4 misho 59:
1.25 misho 60: SCHED_QLOCK(root, taskUNUSE);
1.7 misho 61: TAILQ_FOREACH_SAFE(task, &root->root_unuse, task_node, tmp) {
1.4 misho 62: if (!TASK_ISLOCKED(task)) {
63: TAILQ_REMOVE(&root->root_unuse, task, task_node);
64: break;
65: }
66: }
1.25 misho 67: SCHED_QUNLOCK(root, taskUNUSE);
1.4 misho 68:
69: if (!task) {
70: task = malloc(sizeof(sched_task_t));
71: if (!task) {
72: LOGERR;
73: return NULL;
74: }
75: }
76:
1.9 misho 77: memset(task, 0, sizeof(sched_task_t));
78: task->task_id = (uintptr_t) task;
1.4 misho 79: return task;
80: }
81:
1.13 misho 82: /*
83: * sched_unuseTask() - Unlock and put task to unuse queue
84: *
85: * @task = task
86: * return: always is NULL
87: */
1.16 misho 88: sched_task_t *
1.13 misho 89: sched_unuseTask(sched_task_t * __restrict task)
1.4 misho 90: {
91: TASK_UNLOCK(task);
1.25 misho 92:
1.5 misho 93: TASK_TYPE(task) = taskUNUSE;
1.25 misho 94: insert_task_to(task, &(TASK_ROOT(task))->root_unuse);
95:
1.4 misho 96: task = NULL;
97: return task;
98: }
99:
1.14 misho 100: /*
101: * sched_taskExit() - Exit routine for scheduler task, explicit required for thread tasks
102: *
103: * @task = current task
104: * @retcode = return code
105: * return: return code
106: */
1.16 misho 107: void *
1.14 misho 108: sched_taskExit(sched_task_t *task, intptr_t retcode)
109: {
110: if (!task || !TASK_ROOT(task))
111: return (void*) -1;
112:
113: if (TASK_ROOT(task)->root_hooks.hook_exec.exit)
114: TASK_ROOT(task)->root_hooks.hook_exec.exit(task, (void*) retcode);
115:
116: TASK_ROOT(task)->root_ret = (void*) retcode;
117: return (void*) retcode;
118: }
119:
1.4 misho 120:
1.1 misho 121: /*
1.2 misho 122: * schedRead() - Add READ I/O task to scheduler queue
1.6 misho 123: *
1.1 misho 124: * @root = root task
125: * @func = task execution function
126: * @arg = 1st func argument
1.2 misho 127: * @fd = fd handle
1.5 misho 128: * @opt_data = Optional data
129: * @opt_dlen = Optional data length
1.1 misho 130: * return: NULL error or !=NULL new queued task
131: */
132: sched_task_t *
1.5 misho 133: schedRead(sched_root_task_t * __restrict root, sched_task_func_t func, void *arg, int fd,
134: void *opt_data, size_t opt_dlen)
1.1 misho 135: {
136: sched_task_t *task;
137: void *ptr;
138:
139: if (!root || !func)
140: return NULL;
141:
142: /* get new task */
1.13 misho 143: if (!(task = sched_useTask(root)))
1.4 misho 144: return NULL;
1.1 misho 145:
1.25 misho 146: TASK_FUNC(task) = func;
1.5 misho 147: TASK_TYPE(task) = taskREAD;
148: TASK_ROOT(task) = root;
1.1 misho 149:
150: TASK_ARG(task) = arg;
1.2 misho 151: TASK_FD(task) = fd;
1.1 misho 152:
1.5 misho 153: TASK_DATA(task) = opt_data;
154: TASK_DATLEN(task) = opt_dlen;
155:
1.1 misho 156: if (root->root_hooks.hook_add.read)
157: ptr = root->root_hooks.hook_add.read(task, NULL);
158: else
159: ptr = NULL;
160:
1.25 misho 161: if (!ptr)
162: insert_task_to(task, &root->root_read);
163: else
1.13 misho 164: task = sched_unuseTask(task);
1.1 misho 165:
166: return task;
167: }
168:
169: /*
1.2 misho 170: * schedWrite() - Add WRITE I/O task to scheduler queue
1.6 misho 171: *
1.1 misho 172: * @root = root task
173: * @func = task execution function
174: * @arg = 1st func argument
1.2 misho 175: * @fd = fd handle
1.5 misho 176: * @opt_data = Optional data
177: * @opt_dlen = Optional data length
1.1 misho 178: * return: NULL error or !=NULL new queued task
179: */
180: sched_task_t *
1.5 misho 181: schedWrite(sched_root_task_t * __restrict root, sched_task_func_t func, void *arg, int fd,
182: void *opt_data, size_t opt_dlen)
1.1 misho 183: {
184: sched_task_t *task;
185: void *ptr;
186:
187: if (!root || !func)
188: return NULL;
189:
190: /* get new task */
1.13 misho 191: if (!(task = sched_useTask(root)))
1.4 misho 192: return NULL;
1.1 misho 193:
1.25 misho 194: TASK_FUNC(task) = func;
1.5 misho 195: TASK_TYPE(task) = taskWRITE;
196: TASK_ROOT(task) = root;
1.1 misho 197:
198: TASK_ARG(task) = arg;
1.2 misho 199: TASK_FD(task) = fd;
1.1 misho 200:
1.5 misho 201: TASK_DATA(task) = opt_data;
202: TASK_DATLEN(task) = opt_dlen;
203:
1.1 misho 204: if (root->root_hooks.hook_add.write)
205: ptr = root->root_hooks.hook_add.write(task, NULL);
206: else
207: ptr = NULL;
208:
1.25 misho 209: if (!ptr)
210: insert_task_to(task, &root->root_write);
211: else
1.13 misho 212: task = sched_unuseTask(task);
1.1 misho 213:
214: return task;
215: }
216:
217: /*
1.9 misho 218: * schedNode() - Add NODE task to scheduler queue
219: *
220: * @root = root task
221: * @func = task execution function
222: * @arg = 1st func argument
223: * @fd = fd handle
224: * @opt_data = Optional data
225: * @opt_dlen = Optional data length
226: * return: NULL error or !=NULL new queued task
227: */
228: sched_task_t *
229: schedNode(sched_root_task_t * __restrict root, sched_task_func_t func, void *arg, int fd,
230: void *opt_data, size_t opt_dlen)
231: {
1.25 misho 232: #if SUP_ENABLE != KQ_SUPPORT
1.23 misho 233: sched_SetErr(ENOTSUP, "disabled kqueue support");
234: return NULL;
235: #else
1.9 misho 236: sched_task_t *task;
237: void *ptr;
238:
239: if (!root || !func)
240: return NULL;
241:
242: /* get new task */
1.13 misho 243: if (!(task = sched_useTask(root)))
1.9 misho 244: return NULL;
245:
1.25 misho 246: TASK_FUNC(task) = func;
1.9 misho 247: TASK_TYPE(task) = taskNODE;
248: TASK_ROOT(task) = root;
249:
250: TASK_ARG(task) = arg;
251: TASK_FD(task) = fd;
252:
253: TASK_DATA(task) = opt_data;
254: TASK_DATLEN(task) = opt_dlen;
255:
256: if (root->root_hooks.hook_add.node)
257: ptr = root->root_hooks.hook_add.node(task, NULL);
258: else
259: ptr = NULL;
260:
1.25 misho 261: if (!ptr)
262: insert_task_to(task, &root->root_node);
263: else
1.13 misho 264: task = sched_unuseTask(task);
1.9 misho 265:
266: return task;
1.25 misho 267: #endif /* KQ_SUPPORT */
1.9 misho 268: }
269:
270: /*
271: * schedProc() - Add PROC task to scheduler queue
272: *
273: * @root = root task
274: * @func = task execution function
275: * @arg = 1st func argument
276: * @pid = PID
277: * @opt_data = Optional data
278: * @opt_dlen = Optional data length
279: * return: NULL error or !=NULL new queued task
280: */
281: sched_task_t *
282: schedProc(sched_root_task_t * __restrict root, sched_task_func_t func, void *arg, u_long pid,
283: void *opt_data, size_t opt_dlen)
284: {
1.25 misho 285: #if SUP_ENABLE != KQ_SUPPORT
1.23 misho 286: sched_SetErr(ENOTSUP, "disabled kqueue support");
287: return NULL;
288: #else
1.9 misho 289: sched_task_t *task;
290: void *ptr;
291:
292: if (!root || !func)
293: return NULL;
294:
295: /* get new task */
1.13 misho 296: if (!(task = sched_useTask(root)))
1.9 misho 297: return NULL;
298:
1.25 misho 299: TASK_FUNC(task) = func;
1.9 misho 300: TASK_TYPE(task) = taskPROC;
301: TASK_ROOT(task) = root;
302:
303: TASK_ARG(task) = arg;
304: TASK_VAL(task) = pid;
305:
306: TASK_DATA(task) = opt_data;
307: TASK_DATLEN(task) = opt_dlen;
308:
309: if (root->root_hooks.hook_add.proc)
310: ptr = root->root_hooks.hook_add.proc(task, NULL);
311: else
312: ptr = NULL;
313:
1.25 misho 314: if (!ptr)
315: insert_task_to(task, &root->root_proc);
316: else
1.13 misho 317: task = sched_unuseTask(task);
1.9 misho 318:
319: return task;
1.25 misho 320: #endif /* KQ_SUPPORT */
1.9 misho 321: }
322:
323: /*
324: * schedUser() - Add trigger USER task to scheduler queue
325: *
326: * @root = root task
327: * @func = task execution function
328: * @arg = 1st func argument
329: * @id = Trigger ID
330: * @opt_data = Optional data
331: * @opt_dlen = Optional user's trigger flags
332: * return: NULL error or !=NULL new queued task
333: */
334: sched_task_t *
335: schedUser(sched_root_task_t * __restrict root, sched_task_func_t func, void *arg, u_long id,
336: void *opt_data, size_t opt_dlen)
337: {
1.25 misho 338: #if SUP_ENABLE != KQ_SUPPORT
1.23 misho 339: sched_SetErr(ENOTSUP, "disabled kqueue support");
340: return NULL;
341: #else
1.9 misho 342: #ifndef EVFILT_USER
343: sched_SetErr(ENOTSUP, "Not supported kevent() filter");
344: return NULL;
345: #else
346: sched_task_t *task;
347: void *ptr;
348:
349: if (!root || !func)
350: return NULL;
351:
352: /* get new task */
1.13 misho 353: if (!(task = sched_useTask(root)))
1.9 misho 354: return NULL;
355:
1.25 misho 356: TASK_FUNC(task) = func;
1.9 misho 357: TASK_TYPE(task) = taskUSER;
358: TASK_ROOT(task) = root;
359:
360: TASK_ARG(task) = arg;
361: TASK_VAL(task) = id;
362:
363: TASK_DATA(task) = opt_data;
364: TASK_DATLEN(task) = opt_dlen;
365:
366: if (root->root_hooks.hook_add.user)
367: ptr = root->root_hooks.hook_add.user(task, NULL);
368: else
369: ptr = NULL;
370:
1.25 misho 371: if (!ptr)
372: insert_task_to(task, &root->root_user);
373: else
1.13 misho 374: task = sched_unuseTask(task);
1.9 misho 375:
376: return task;
1.23 misho 377: #endif /* EVFILT_USER */
1.25 misho 378: #endif /* KQ_SUPPORT */
1.9 misho 379: }
380:
381: /*
382: * schedSignal() - Add SIGNAL task to scheduler queue
383: *
384: * @root = root task
385: * @func = task execution function
386: * @arg = 1st func argument
387: * @sig = Signal
388: * @opt_data = Optional data
389: * @opt_dlen = Optional data length
390: * return: NULL error or !=NULL new queued task
391: */
392: sched_task_t *
393: schedSignal(sched_root_task_t * __restrict root, sched_task_func_t func, void *arg, u_long sig,
394: void *opt_data, size_t opt_dlen)
395: {
1.25 misho 396: #if SUP_ENABLE != KQ_SUPPORT
1.23 misho 397: sched_SetErr(ENOTSUP, "disabled kqueue support");
398: return NULL;
399: #else
1.9 misho 400: sched_task_t *task;
401: void *ptr;
402:
403: if (!root || !func)
404: return NULL;
405:
406: /* get new task */
1.13 misho 407: if (!(task = sched_useTask(root)))
1.9 misho 408: return NULL;
409:
1.25 misho 410: TASK_FUNC(task) = func;
1.9 misho 411: TASK_TYPE(task) = taskSIGNAL;
412: TASK_ROOT(task) = root;
413:
414: TASK_ARG(task) = arg;
415: TASK_VAL(task) = sig;
416:
417: TASK_DATA(task) = opt_data;
418: TASK_DATLEN(task) = opt_dlen;
419:
420: if (root->root_hooks.hook_add.signal)
421: ptr = root->root_hooks.hook_add.signal(task, NULL);
422: else
423: ptr = NULL;
424:
1.25 misho 425: if (!ptr)
426: insert_task_to(task, &root->root_signal);
427: else
1.13 misho 428: task = sched_unuseTask(task);
1.9 misho 429:
430: return task;
1.25 misho 431: #endif /* KQ_SUPPORT */
1.9 misho 432: }
433:
434: /*
1.8 misho 435: * schedAlarm() - Add ALARM task to scheduler queue
436: *
437: * @root = root task
438: * @func = task execution function
439: * @arg = 1st func argument
440: * @ts = timeout argument structure, minimum alarm timer resolution is 1msec!
1.17 misho 441: * @opt_data = Alarm timer ID
1.8 misho 442: * @opt_dlen = Optional data length
443: * return: NULL error or !=NULL new queued task
444: */
445: sched_task_t *
446: schedAlarm(sched_root_task_t * __restrict root, sched_task_func_t func, void *arg, struct timespec ts,
447: void *opt_data, size_t opt_dlen)
448: {
1.25 misho 449: #if SUP_ENABLE != KQ_SUPPORT
1.23 misho 450: sched_SetErr(ENOTSUP, "disabled kqueue support");
451: return NULL;
452: #else
1.8 misho 453: sched_task_t *task;
454: void *ptr;
455:
456: if (!root || !func)
457: return NULL;
458:
459: /* get new task */
1.13 misho 460: if (!(task = sched_useTask(root)))
1.8 misho 461: return NULL;
462:
1.25 misho 463: TASK_FUNC(task) = func;
1.8 misho 464: TASK_TYPE(task) = taskALARM;
465: TASK_ROOT(task) = root;
466:
467: TASK_ARG(task) = arg;
468: TASK_TS(task) = ts;
469:
470: TASK_DATA(task) = opt_data;
471: TASK_DATLEN(task) = opt_dlen;
472:
473: if (root->root_hooks.hook_add.alarm)
474: ptr = root->root_hooks.hook_add.alarm(task, NULL);
475: else
476: ptr = NULL;
477:
1.25 misho 478: if (!ptr)
479: insert_task_to(task, &root->root_alarm);
480: else
1.13 misho 481: task = sched_unuseTask(task);
1.8 misho 482:
483: return task;
1.25 misho 484: #endif /* KQ_SUPPORT */
1.8 misho 485: }
486:
1.11 misho 487: #ifdef AIO_SUPPORT
488: /*
489: * schedAIO() - Add AIO task to scheduler queue
490: *
491: * @root = root task
492: * @func = task execution function
493: * @arg = 1st func argument
494: * @acb = AIO cb structure address
495: * @opt_data = Optional data
496: * @opt_dlen = Optional data length
497: * return: NULL error or !=NULL new queued task
498: */
499: sched_task_t *
500: schedAIO(sched_root_task_t * __restrict root, sched_task_func_t func, void *arg,
501: struct aiocb * __restrict acb, void *opt_data, size_t opt_dlen)
502: {
1.25 misho 503: #if SUP_ENABLE != KQ_SUPPORT
1.23 misho 504: sched_SetErr(ENOTSUP, "disabled kqueue support");
505: return NULL;
506: #else
1.11 misho 507: sched_task_t *task;
508: void *ptr;
509:
510: if (!root || !func || !acb || !opt_dlen)
511: return NULL;
512:
513: /* get new task */
1.13 misho 514: if (!(task = sched_useTask(root)))
1.11 misho 515: return NULL;
516:
1.25 misho 517: TASK_FUNC(task) = func;
1.11 misho 518: TASK_TYPE(task) = taskAIO;
519: TASK_ROOT(task) = root;
520:
521: TASK_ARG(task) = arg;
522: TASK_VAL(task) = (u_long) acb;
523:
524: TASK_DATA(task) = opt_data;
525: TASK_DATLEN(task) = opt_dlen;
526:
527: if (root->root_hooks.hook_add.aio)
528: ptr = root->root_hooks.hook_add.aio(task, NULL);
529: else
530: ptr = NULL;
531:
1.25 misho 532: if (!ptr)
533: insert_task_to(task, &root->root_aio);
534: else
1.13 misho 535: task = sched_unuseTask(task);
1.11 misho 536:
537: return task;
1.25 misho 538: #endif /* KQ_SUPPORT */
1.11 misho 539: }
540:
541: /*
542: * schedAIORead() - Add AIO read task to scheduler queue
543: *
544: * @root = root task
545: * @func = task execution function
546: * @arg = 1st func argument
547: * @fd = file descriptor
548: * @buffer = Buffer
549: * @buflen = Buffer length
550: * @offset = Offset from start of file, if =-1 from current position
551: * return: NULL error or !=NULL new queued task
552: */
1.16 misho 553: sched_task_t *
1.11 misho 554: schedAIORead(sched_root_task_t * __restrict root, sched_task_func_t func, void *arg, int fd,
555: void *buffer, size_t buflen, off_t offset)
556: {
1.25 misho 557: #if SUP_ENABLE != KQ_SUPPORT
1.23 misho 558: sched_SetErr(ENOTSUP, "disabled kqueue support");
559: return NULL;
560: #else
1.11 misho 561: struct aiocb *acb;
562: off_t off;
563:
564: if (!root || !func || !buffer || !buflen)
565: return NULL;
566:
567: if (offset == (off_t) -1) {
568: off = lseek(fd, 0, SEEK_CUR);
569: if (off == -1) {
570: LOGERR;
571: return NULL;
572: }
573: } else
574: off = offset;
575:
576: if (!(acb = malloc(sizeof(struct aiocb)))) {
577: LOGERR;
578: return NULL;
579: } else
580: memset(acb, 0, sizeof(struct aiocb));
581:
582: acb->aio_fildes = fd;
583: acb->aio_nbytes = buflen;
584: acb->aio_buf = buffer;
585: acb->aio_offset = off;
586: acb->aio_sigevent.sigev_notify = SIGEV_KEVENT;
587: acb->aio_sigevent.sigev_notify_kqueue = root->root_kq;
588: acb->aio_sigevent.sigev_value.sival_ptr = acb;
589:
590: if (aio_read(acb)) {
591: LOGERR;
592: free(acb);
593: return NULL;
594: }
595:
596: return schedAIO(root, func, arg, acb, buffer, buflen);
1.25 misho 597: #endif /* KQ_SUPPORT */
1.11 misho 598: }
599:
600: /*
601: * schedAIOWrite() - Add AIO write task to scheduler queue
602: *
603: * @root = root task
604: * @func = task execution function
605: * @arg = 1st func argument
606: * @fd = file descriptor
607: * @buffer = Buffer
608: * @buflen = Buffer length
609: * @offset = Offset from start of file, if =-1 from current position
610: * return: NULL error or !=NULL new queued task
611: */
1.16 misho 612: sched_task_t *
1.11 misho 613: schedAIOWrite(sched_root_task_t * __restrict root, sched_task_func_t func, void *arg, int fd,
614: void *buffer, size_t buflen, off_t offset)
615: {
1.25 misho 616: #if SUP_ENABLE != KQ_SUPPORT
1.23 misho 617: sched_SetErr(ENOTSUP, "disabled kqueue support");
618: return NULL;
619: #else
1.11 misho 620: struct aiocb *acb;
621: off_t off;
622:
623: if (!root || !func || !buffer || !buflen)
624: return NULL;
625:
626: if (offset == (off_t) -1) {
627: off = lseek(fd, 0, SEEK_CUR);
628: if (off == -1) {
629: LOGERR;
630: return NULL;
631: }
632: } else
633: off = offset;
634:
635: if (!(acb = malloc(sizeof(struct aiocb)))) {
636: LOGERR;
637: return NULL;
638: } else
639: memset(acb, 0, sizeof(struct aiocb));
640:
641: acb->aio_fildes = fd;
642: acb->aio_nbytes = buflen;
643: acb->aio_buf = buffer;
644: acb->aio_offset = off;
645: acb->aio_sigevent.sigev_notify = SIGEV_KEVENT;
646: acb->aio_sigevent.sigev_notify_kqueue = root->root_kq;
647: acb->aio_sigevent.sigev_value.sival_ptr = acb;
648:
649: if (aio_write(acb)) {
650: LOGERR;
651: free(acb);
652: return NULL;
653: }
654:
655: return schedAIO(root, func, arg, acb, buffer, buflen);
1.25 misho 656: #endif /* KQ_SUPPORT */
1.11 misho 657: }
658:
659: #ifdef EVFILT_LIO
660: /*
661: * schedLIO() - Add AIO bulk tasks to scheduler queue
662: *
663: * @root = root task
664: * @func = task execution function
665: * @arg = 1st func argument
666: * @acbs = AIO cb structure addresses
667: * @opt_data = Optional data
668: * @opt_dlen = Optional data length
669: * return: NULL error or !=NULL new queued task
670: */
671: sched_task_t *
672: schedLIO(sched_root_task_t * __restrict root, sched_task_func_t func, void *arg,
673: struct aiocb ** __restrict acbs, void *opt_data, size_t opt_dlen)
674: {
1.25 misho 675: #if SUP_ENABLE != KQ_SUPPORT
1.23 misho 676: sched_SetErr(ENOTSUP, "disabled kqueue support");
677: return NULL;
678: #else
1.11 misho 679: sched_task_t *task;
680: void *ptr;
681:
682: if (!root || !func || !acbs || !opt_dlen)
683: return NULL;
684:
685: /* get new task */
1.13 misho 686: if (!(task = sched_useTask(root)))
1.11 misho 687: return NULL;
688:
1.25 misho 689: TASK_FUNC(task) = func;
1.11 misho 690: TASK_TYPE(task) = taskLIO;
691: TASK_ROOT(task) = root;
692:
693: TASK_ARG(task) = arg;
694: TASK_VAL(task) = (u_long) acbs;
695:
696: TASK_DATA(task) = opt_data;
697: TASK_DATLEN(task) = opt_dlen;
698:
699: if (root->root_hooks.hook_add.lio)
700: ptr = root->root_hooks.hook_add.lio(task, NULL);
701: else
702: ptr = NULL;
703:
1.25 misho 704: if (!ptr)
705: insert_task_to(task, &root->root_lio);
706: else
1.13 misho 707: task = sched_unuseTask(task);
1.11 misho 708:
709: return task;
1.25 misho 710: #endif /* KQ_SUPPORT */
1.11 misho 711: }
712:
713: /*
714: * schedLIORead() - Add list of AIO read tasks to scheduler queue
715: *
716: * @root = root task
717: * @func = task execution function
718: * @arg = 1st func argument
719: * @fd = file descriptor
720: * @bufs = Buffer's list
721: * @nbufs = Number of Buffers
722: * @offset = Offset from start of file, if =-1 from current position
723: * return: NULL error or !=NULL new queued task
724: */
725: sched_task_t *
726: schedLIORead(sched_root_task_t * __restrict root, sched_task_func_t func, void *arg, int fd,
727: struct iovec *bufs, size_t nbufs, off_t offset)
728: {
1.25 misho 729: #if SUP_ENABLE != KQ_SUPPORT
1.23 misho 730: sched_SetErr(ENOTSUP, "disabled kqueue support");
731: return NULL;
732: #else
1.11 misho 733: struct sigevent sig;
734: struct aiocb **acb;
735: off_t off;
736: register int i;
737:
738: if (!root || !func || !bufs || !nbufs)
739: return NULL;
740:
741: if (offset == (off_t) -1) {
742: off = lseek(fd, 0, SEEK_CUR);
743: if (off == -1) {
744: LOGERR;
745: return NULL;
746: }
747: } else
748: off = offset;
749:
750: if (!(acb = calloc(sizeof(void*), nbufs))) {
751: LOGERR;
752: return NULL;
753: } else
754: memset(acb, 0, sizeof(void*) * nbufs);
755: for (i = 0; i < nbufs; off += bufs[i++].iov_len) {
756: acb[i] = malloc(sizeof(struct aiocb));
757: if (!acb[i]) {
758: LOGERR;
759: for (i = 0; i < nbufs; i++)
760: if (acb[i])
761: free(acb[i]);
762: free(acb);
763: return NULL;
764: } else
765: memset(acb[i], 0, sizeof(struct aiocb));
766: acb[i]->aio_fildes = fd;
767: acb[i]->aio_nbytes = bufs[i].iov_len;
768: acb[i]->aio_buf = bufs[i].iov_base;
769: acb[i]->aio_offset = off;
770: acb[i]->aio_lio_opcode = LIO_READ;
771: }
772: memset(&sig, 0, sizeof sig);
773: sig.sigev_notify = SIGEV_KEVENT;
774: sig.sigev_notify_kqueue = root->root_kq;
775: sig.sigev_value.sival_ptr = acb;
776:
777: if (lio_listio(LIO_NOWAIT, acb, nbufs, &sig)) {
778: LOGERR;
779: for (i = 0; i < nbufs; i++)
780: if (acb[i])
781: free(acb[i]);
782: free(acb);
783: return NULL;
784: }
785:
786: return schedLIO(root, func, arg, (void*) acb, bufs, nbufs);
1.25 misho 787: #endif /* KQ_SUPPORT */
1.11 misho 788: }
789:
790: /*
791: * schedLIOWrite() - Add list of AIO write tasks to scheduler queue
792: *
793: * @root = root task
794: * @func = task execution function
795: * @arg = 1st func argument
796: * @fd = file descriptor
797: * @bufs = Buffer's list
798: * @nbufs = Number of Buffers
799: * @offset = Offset from start of file, if =-1 from current position
800: * return: NULL error or !=NULL new queued task
801: */
1.16 misho 802: sched_task_t *
1.11 misho 803: schedLIOWrite(sched_root_task_t * __restrict root, sched_task_func_t func, void *arg, int fd,
804: struct iovec *bufs, size_t nbufs, off_t offset)
805: {
1.25 misho 806: #if SUP_ENABLE != KQ_SUPPORT
1.23 misho 807: sched_SetErr(ENOTSUP, "disabled kqueue support");
808: return NULL;
809: #else
1.11 misho 810: struct sigevent sig;
811: struct aiocb **acb;
812: off_t off;
813: register int i;
814:
815: if (!root || !func || !bufs || !nbufs)
816: return NULL;
817:
818: if (offset == (off_t) -1) {
819: off = lseek(fd, 0, SEEK_CUR);
820: if (off == -1) {
821: LOGERR;
822: return NULL;
823: }
824: } else
825: off = offset;
826:
827: if (!(acb = calloc(sizeof(void*), nbufs))) {
828: LOGERR;
829: return NULL;
830: } else
831: memset(acb, 0, sizeof(void*) * nbufs);
832: for (i = 0; i < nbufs; off += bufs[i++].iov_len) {
833: acb[i] = malloc(sizeof(struct aiocb));
834: if (!acb[i]) {
835: LOGERR;
836: for (i = 0; i < nbufs; i++)
837: if (acb[i])
838: free(acb[i]);
839: free(acb);
840: return NULL;
841: } else
842: memset(acb[i], 0, sizeof(struct aiocb));
843: acb[i]->aio_fildes = fd;
844: acb[i]->aio_nbytes = bufs[i].iov_len;
845: acb[i]->aio_buf = bufs[i].iov_base;
846: acb[i]->aio_offset = off;
847: acb[i]->aio_lio_opcode = LIO_WRITE;
848: }
849: memset(&sig, 0, sizeof sig);
850: sig.sigev_notify = SIGEV_KEVENT;
851: sig.sigev_notify_kqueue = root->root_kq;
852: sig.sigev_value.sival_ptr = acb;
853:
854: if (lio_listio(LIO_NOWAIT, acb, nbufs, &sig)) {
855: LOGERR;
856: for (i = 0; i < nbufs; i++)
857: if (acb[i])
858: free(acb[i]);
859: free(acb);
860: return NULL;
861: }
862:
863: return schedLIO(root, func, arg, (void*) acb, bufs, nbufs);
1.25 misho 864: #endif /* KQ_SUPPORT */
1.11 misho 865: }
866: #endif /* EVFILT_LIO */
867: #endif /* AIO_SUPPORT */
868:
1.8 misho 869: /*
1.1 misho 870: * schedTimer() - Add TIMER task to scheduler queue
1.6 misho 871: *
1.1 misho 872: * @root = root task
873: * @func = task execution function
874: * @arg = 1st func argument
1.5 misho 875: * @ts = timeout argument structure
876: * @opt_data = Optional data
877: * @opt_dlen = Optional data length
1.1 misho 878: * return: NULL error or !=NULL new queued task
879: */
880: sched_task_t *
1.5 misho 881: schedTimer(sched_root_task_t * __restrict root, sched_task_func_t func, void *arg, struct timespec ts,
882: void *opt_data, size_t opt_dlen)
1.1 misho 883: {
1.9 misho 884: sched_task_t *task, *tmp, *t = NULL;
1.1 misho 885: void *ptr;
1.5 misho 886: struct timespec now;
1.1 misho 887:
888: if (!root || !func)
889: return NULL;
890:
891: /* get new task */
1.13 misho 892: if (!(task = sched_useTask(root)))
1.4 misho 893: return NULL;
1.1 misho 894:
1.25 misho 895: TASK_FUNC(task) = func;
1.5 misho 896: TASK_TYPE(task) = taskTIMER;
897: TASK_ROOT(task) = root;
1.1 misho 898:
899: TASK_ARG(task) = arg;
900:
1.5 misho 901: TASK_DATA(task) = opt_data;
902: TASK_DATLEN(task) = opt_dlen;
903:
1.1 misho 904: /* calculate timeval structure */
1.5 misho 905: clock_gettime(CLOCK_MONOTONIC, &now);
906: now.tv_sec += ts.tv_sec;
907: now.tv_nsec += ts.tv_nsec;
908: if (now.tv_nsec >= 1000000000L) {
1.1 misho 909: now.tv_sec++;
1.5 misho 910: now.tv_nsec -= 1000000000L;
911: } else if (now.tv_nsec < 0) {
1.1 misho 912: now.tv_sec--;
1.5 misho 913: now.tv_nsec += 1000000000L;
1.1 misho 914: }
1.5 misho 915: TASK_TS(task) = now;
1.1 misho 916:
917: if (root->root_hooks.hook_add.timer)
918: ptr = root->root_hooks.hook_add.timer(task, NULL);
919: else
920: ptr = NULL;
921:
922: if (!ptr) {
1.25 misho 923: SCHED_QLOCK(root, taskTIMER);
1.1 misho 924: #ifdef TIMER_WITHOUT_SORT
1.25 misho 925: TAILQ_INSERT_TAIL(&root->root_timer, task, task_node);
1.1 misho 926: #else
1.9 misho 927: TAILQ_FOREACH_SAFE(t, &root->root_timer, task_node, tmp)
1.5 misho 928: if (sched_timespeccmp(&TASK_TS(task), &TASK_TS(t), -) < 1)
1.1 misho 929: break;
930: if (!t)
1.25 misho 931: TAILQ_INSERT_TAIL(&root->root_timer, task, task_node);
1.1 misho 932: else
1.25 misho 933: TAILQ_INSERT_BEFORE(t, task, task_node);
1.5 misho 934: #endif
1.25 misho 935: SCHED_QUNLOCK(root, taskTIMER);
1.4 misho 936: } else
1.13 misho 937: task = sched_unuseTask(task);
1.1 misho 938:
939: return task;
940: }
941:
942: /*
943: * schedEvent() - Add EVENT task to scheduler queue
1.6 misho 944: *
1.1 misho 945: * @root = root task
946: * @func = task execution function
947: * @arg = 1st func argument
1.2 misho 948: * @val = additional func argument
1.5 misho 949: * @opt_data = Optional data
950: * @opt_dlen = Optional data length
1.1 misho 951: * return: NULL error or !=NULL new queued task
952: */
953: sched_task_t *
1.5 misho 954: schedEvent(sched_root_task_t * __restrict root, sched_task_func_t func, void *arg, u_long val,
955: void *opt_data, size_t opt_dlen)
1.1 misho 956: {
957: sched_task_t *task;
958: void *ptr;
959:
960: if (!root || !func)
961: return NULL;
962:
963: /* get new task */
1.13 misho 964: if (!(task = sched_useTask(root)))
1.4 misho 965: return NULL;
1.1 misho 966:
1.25 misho 967: TASK_FUNC(task) = func;
1.5 misho 968: TASK_TYPE(task) = taskEVENT;
969: TASK_ROOT(task) = root;
1.1 misho 970:
971: TASK_ARG(task) = arg;
1.2 misho 972: TASK_VAL(task) = val;
1.1 misho 973:
1.5 misho 974: TASK_DATA(task) = opt_data;
975: TASK_DATLEN(task) = opt_dlen;
976:
1.1 misho 977: if (root->root_hooks.hook_add.event)
978: ptr = root->root_hooks.hook_add.event(task, NULL);
979: else
980: ptr = NULL;
981:
1.25 misho 982: if (!ptr)
983: insert_task_to(task, &root->root_event);
984: else
1.13 misho 985: task = sched_unuseTask(task);
1.1 misho 986:
987: return task;
988: }
989:
990:
991: /*
1.12 misho 992: * schedTask() - Add regular task to scheduler queue
1.6 misho 993: *
1.1 misho 994: * @root = root task
995: * @func = task execution function
996: * @arg = 1st func argument
1.12 misho 997: * @prio = regular task priority, 0 is hi priority for regular tasks
1.5 misho 998: * @opt_data = Optional data
999: * @opt_dlen = Optional data length
1.1 misho 1000: * return: NULL error or !=NULL new queued task
1001: */
1002: sched_task_t *
1.12 misho 1003: schedTask(sched_root_task_t * __restrict root, sched_task_func_t func, void *arg, u_long prio,
1.5 misho 1004: void *opt_data, size_t opt_dlen)
1.1 misho 1005: {
1.12 misho 1006: sched_task_t *task, *tmp, *t = NULL;
1.1 misho 1007: void *ptr;
1008:
1009: if (!root || !func)
1010: return NULL;
1011:
1012: /* get new task */
1.13 misho 1013: if (!(task = sched_useTask(root)))
1.4 misho 1014: return NULL;
1.1 misho 1015:
1.25 misho 1016: TASK_FUNC(task) = func;
1.12 misho 1017: TASK_TYPE(task) = taskTASK;
1.5 misho 1018: TASK_ROOT(task) = root;
1.1 misho 1019:
1020: TASK_ARG(task) = arg;
1.12 misho 1021: TASK_VAL(task) = prio;
1.1 misho 1022:
1.5 misho 1023: TASK_DATA(task) = opt_data;
1024: TASK_DATLEN(task) = opt_dlen;
1025:
1.12 misho 1026: if (root->root_hooks.hook_add.task)
1027: ptr = root->root_hooks.hook_add.task(task, NULL);
1.1 misho 1028: else
1029: ptr = NULL;
1030:
1.5 misho 1031: if (!ptr) {
1.25 misho 1032: SCHED_QLOCK(root, taskTASK);
1.12 misho 1033: TAILQ_FOREACH_SAFE(t, &root->root_task, task_node, tmp)
1034: if (TASK_VAL(task) < TASK_VAL(t))
1035: break;
1036: if (!t)
1.25 misho 1037: TAILQ_INSERT_TAIL(&root->root_task, task, task_node);
1.12 misho 1038: else
1.25 misho 1039: TAILQ_INSERT_BEFORE(t, task, task_node);
1040: SCHED_QUNLOCK(root, taskTASK);
1.5 misho 1041: } else
1.13 misho 1042: task = sched_unuseTask(task);
1.1 misho 1043:
1044: return task;
1045: }
1046:
1047: /*
1.10 misho 1048: * schedSuspend() - Add Suspended task to scheduler queue
1049: *
1050: * @root = root task
1051: * @func = task execution function
1052: * @arg = 1st func argument
1053: * @id = Trigger ID
1054: * @opt_data = Optional data
1055: * @opt_dlen = Optional data length
1056: * return: NULL error or !=NULL new queued task
1057: */
1058: sched_task_t *
1059: schedSuspend(sched_root_task_t * __restrict root, sched_task_func_t func, void *arg, u_long id,
1060: void *opt_data, size_t opt_dlen)
1061: {
1062: sched_task_t *task;
1063: void *ptr;
1064:
1065: if (!root || !func)
1066: return NULL;
1067:
1068: /* get new task */
1.13 misho 1069: if (!(task = sched_useTask(root)))
1.10 misho 1070: return NULL;
1071:
1.25 misho 1072: TASK_FUNC(task) = func;
1.10 misho 1073: TASK_TYPE(task) = taskSUSPEND;
1074: TASK_ROOT(task) = root;
1075:
1076: TASK_ARG(task) = arg;
1077: TASK_VAL(task) = id;
1078:
1079: TASK_DATA(task) = opt_data;
1080: TASK_DATLEN(task) = opt_dlen;
1081:
1082: if (root->root_hooks.hook_add.suspend)
1083: ptr = root->root_hooks.hook_add.suspend(task, NULL);
1084: else
1085: ptr = NULL;
1086:
1.25 misho 1087: if (!ptr)
1088: insert_task_to(task, &root->root_suspend);
1089: else
1.13 misho 1090: task = sched_unuseTask(task);
1.10 misho 1091:
1092: return task;
1093: }
1094:
1095: /*
1.1 misho 1096: * schedCallOnce() - Call once from scheduler
1.6 misho 1097: *
1.1 misho 1098: * @root = root task
1099: * @func = task execution function
1100: * @arg = 1st func argument
1.2 misho 1101: * @val = additional func argument
1.5 misho 1102: * @opt_data = Optional data
1103: * @opt_dlen = Optional data length
1.2 misho 1104: * return: return value from called func
1.1 misho 1105: */
1106: sched_task_t *
1.5 misho 1107: schedCallOnce(sched_root_task_t * __restrict root, sched_task_func_t func, void *arg, u_long val,
1108: void *opt_data, size_t opt_dlen)
1.1 misho 1109: {
1110: sched_task_t *task;
1.2 misho 1111: void *ret;
1.1 misho 1112:
1113: if (!root || !func)
1114: return NULL;
1115:
1116: /* get new task */
1.13 misho 1117: if (!(task = sched_useTask(root)))
1.4 misho 1118: return NULL;
1.1 misho 1119:
1.25 misho 1120: TASK_FUNC(task) = func;
1.5 misho 1121: TASK_TYPE(task) = taskEVENT;
1122: TASK_ROOT(task) = root;
1.1 misho 1123:
1124: TASK_ARG(task) = arg;
1.2 misho 1125: TASK_VAL(task) = val;
1.1 misho 1126:
1.5 misho 1127: TASK_DATA(task) = opt_data;
1128: TASK_DATLEN(task) = opt_dlen;
1129:
1.2 misho 1130: ret = schedCall(task);
1.1 misho 1131:
1.13 misho 1132: sched_unuseTask(task);
1.2 misho 1133: return ret;
1.1 misho 1134: }
1.13 misho 1135:
1136: /*
1137: * schedThread() - Add thread task to scheduler queue
1138: *
1139: * @root = root task
1140: * @func = task execution function
1141: * @arg = 1st func argument
1.15 misho 1142: * @ss = stack size
1.13 misho 1143: * @opt_data = Optional data
1144: * @opt_dlen = Optional data length
1145: * return: NULL error or !=NULL new queued task
1146: */
1147: sched_task_t *
1.21 misho 1148: schedThread(sched_root_task_t * __restrict root, sched_task_func_t func, void *arg,
1.15 misho 1149: size_t ss, void *opt_data, size_t opt_dlen)
1.13 misho 1150: {
1151: #ifndef HAVE_LIBPTHREAD
1152: sched_SetErr(ENOTSUP, "Not supported thread tasks");
1153: return NULL;
1154: #endif
1155: sched_task_t *task;
1156: pthread_attr_t attr;
1.25 misho 1157: void *ptr;
1.13 misho 1158:
1159: if (!root || !func)
1160: return NULL;
1161:
1162: /* get new task */
1.25 misho 1163: if (!(task = sched_useTask(root)))
1.13 misho 1164: return NULL;
1165:
1.25 misho 1166: TASK_FUNC(task) = func;
1.13 misho 1167: TASK_TYPE(task) = taskTHREAD;
1168: TASK_ROOT(task) = root;
1169:
1170: TASK_ARG(task) = arg;
1171:
1172: TASK_DATA(task) = opt_data;
1173: TASK_DATLEN(task) = opt_dlen;
1174:
1175: pthread_attr_init(&attr);
1.25 misho 1176: pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
1.15 misho 1177: if (ss && (errno = pthread_attr_setstacksize(&attr, ss))) {
1178: LOGERR;
1179: pthread_attr_destroy(&attr);
1180: return sched_unuseTask(task);
1181: }
1182: if ((errno = pthread_attr_getstacksize(&attr, &ss))) {
1183: LOGERR;
1184: pthread_attr_destroy(&attr);
1185: return sched_unuseTask(task);
1186: } else
1.21 misho 1187: TASK_FLAG(task) = ss;
1.25 misho 1188:
1.15 misho 1189: #ifdef SCHED_RR
1190: pthread_attr_setschedpolicy(&attr, SCHED_RR);
1191: #else
1192: pthread_attr_setschedpolicy(&attr, SCHED_OTHER);
1193: #endif
1.21 misho 1194:
1.25 misho 1195: if (root->root_hooks.hook_add.thread)
1196: ptr = root->root_hooks.hook_add.thread(task, &attr);
1197: else
1198: ptr = NULL;
1199:
1200: if (!ptr)
1201: insert_task_to(task, &root->root_thread);
1202: else
1203: task = sched_unuseTask(task);
1.21 misho 1204:
1.13 misho 1205: pthread_attr_destroy(&attr);
1206: return task;
1207: }
1208:
1.17 misho 1209: /*
1210: * schedRTC() - Add RTC task to scheduler queue
1211: *
1212: * @root = root task
1213: * @func = task execution function
1214: * @arg = 1st func argument
1215: * @ts = timeout argument structure, minimum alarm timer resolution is 1msec!
1216: * @opt_data = Optional RTC ID
1.18 misho 1217: * @opt_dlen = Optional data length
1.17 misho 1218: * return: NULL error or !=NULL new queued task
1219: */
1220: sched_task_t *
1221: schedRTC(sched_root_task_t * __restrict root, sched_task_func_t func, void *arg, struct timespec ts,
1222: void *opt_data, size_t opt_dlen)
1223: {
1.25.2.1 misho 1224: #if defined(HAVE_LIBRT) && defined(HAVE_TIMER_CREATE) && \
1225: defined(HAVE_TIMER_SETTIME) && defined(HAVE_TIMER_DELETE)
1.17 misho 1226: sched_task_t *task;
1227: void *ptr;
1228:
1229: if (!root || !func)
1230: return NULL;
1231:
1232: /* get new task */
1233: if (!(task = sched_useTask(root)))
1234: return NULL;
1235:
1.25 misho 1236: TASK_FUNC(task) = func;
1.17 misho 1237: TASK_TYPE(task) = taskRTC;
1238: TASK_ROOT(task) = root;
1239:
1240: TASK_ARG(task) = arg;
1241: TASK_TS(task) = ts;
1242:
1243: TASK_DATA(task) = opt_data;
1244: TASK_DATLEN(task) = opt_dlen;
1245:
1246: if (root->root_hooks.hook_add.rtc)
1247: ptr = root->root_hooks.hook_add.rtc(task, NULL);
1248: else
1249: ptr = NULL;
1250:
1.25 misho 1251: if (!ptr)
1252: insert_task_to(task, &root->root_rtc);
1253: else
1.17 misho 1254: task = sched_unuseTask(task);
1255:
1256: return task;
1257: #else
1258: sched_SetErr(ENOTSUP, "Not supported realtime clock extensions");
1259: return NULL;
1260: #endif
1261: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>