Annotation of libaitsched/src/tasks.c, revision 1.7.4.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.7.4.1 ! misho 6: * $Id: tasks.c,v 1.7 2012/05/14 12:09:13 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.6 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:
48:
1.4 misho 49: #pragma GCC visibility push(hidden)
50:
51: inline sched_task_t *
52: _sched_useTask(sched_root_task_t * __restrict root)
53: {
1.7 misho 54: sched_task_t *task, *tmp;
1.4 misho 55:
1.7 misho 56: TAILQ_FOREACH_SAFE(task, &root->root_unuse, task_node, tmp) {
1.4 misho 57: if (!TASK_ISLOCKED(task)) {
1.5 misho 58: #ifdef HAVE_LIBPTHREAD
59: pthread_mutex_lock(&root->root_mtx[taskUNUSE]);
60: #endif
1.4 misho 61: TAILQ_REMOVE(&root->root_unuse, task, task_node);
1.5 misho 62: #ifdef HAVE_LIBPTHREAD
63: pthread_mutex_unlock(&root->root_mtx[taskUNUSE]);
64: #endif
1.4 misho 65: break;
66: }
67: }
68:
69: if (!task) {
70: task = malloc(sizeof(sched_task_t));
71: if (!task) {
72: LOGERR;
73: return NULL;
74: }
75: }
76:
77: return task;
78: }
79:
80: inline sched_task_t *
81: _sched_unuseTask(sched_task_t * __restrict task)
82: {
83: TASK_UNLOCK(task);
1.5 misho 84: TASK_TYPE(task) = taskUNUSE;
85: #ifdef HAVE_LIBPTHREAD
86: pthread_mutex_lock(&TASK_ROOT(task)->root_mtx[taskUNUSE]);
87: #endif
88: TAILQ_INSERT_TAIL(&TASK_ROOT(task)->root_unuse, task, task_node);
89: #ifdef HAVE_LIBPTHREAD
90: pthread_mutex_unlock(&TASK_ROOT(task)->root_mtx[taskUNUSE]);
91: #endif
1.4 misho 92: task = NULL;
93:
94: return task;
95: }
96:
97: #pragma GCC visibility pop
98:
99:
1.1 misho 100: /*
1.2 misho 101: * schedRead() - Add READ I/O task to scheduler queue
1.6 misho 102: *
1.1 misho 103: * @root = root task
104: * @func = task execution function
105: * @arg = 1st func argument
1.2 misho 106: * @fd = fd handle
1.5 misho 107: * @opt_data = Optional data
108: * @opt_dlen = Optional data length
1.1 misho 109: * return: NULL error or !=NULL new queued task
110: */
111: sched_task_t *
1.5 misho 112: schedRead(sched_root_task_t * __restrict root, sched_task_func_t func, void *arg, int fd,
113: void *opt_data, size_t opt_dlen)
1.1 misho 114: {
115: sched_task_t *task;
116: void *ptr;
117:
118: if (!root || !func)
119: return NULL;
120:
121: /* get new task */
1.4 misho 122: if (!(task = _sched_useTask(root)))
123: return NULL;
1.1 misho 124:
125: memset(task, 0, sizeof(sched_task_t));
126: task->task_id = 0;
1.4 misho 127: task->task_lock = 0;
1.1 misho 128: task->task_func = func;
1.5 misho 129: TASK_TYPE(task) = taskREAD;
130: TASK_ROOT(task) = root;
1.1 misho 131:
132: TASK_ARG(task) = arg;
1.2 misho 133: TASK_FD(task) = fd;
1.1 misho 134:
1.5 misho 135: TASK_DATA(task) = opt_data;
136: TASK_DATLEN(task) = opt_dlen;
137:
1.1 misho 138: if (root->root_hooks.hook_add.read)
139: ptr = root->root_hooks.hook_add.read(task, NULL);
140: else
141: ptr = NULL;
142:
1.5 misho 143: if (!ptr) {
144: #ifdef HAVE_LIBPTHREAD
145: pthread_mutex_lock(&root->root_mtx[taskREAD]);
146: #endif
1.1 misho 147: TAILQ_INSERT_TAIL(&root->root_read, task, task_node);
1.5 misho 148: #ifdef HAVE_LIBPTHREAD
149: pthread_mutex_unlock(&root->root_mtx[taskREAD]);
150: #endif
151: } else
1.4 misho 152: task = _sched_unuseTask(task);
1.1 misho 153:
154: return task;
155: }
156:
157: /*
1.2 misho 158: * schedWrite() - Add WRITE I/O task to scheduler queue
1.6 misho 159: *
1.1 misho 160: * @root = root task
161: * @func = task execution function
162: * @arg = 1st func argument
1.2 misho 163: * @fd = fd handle
1.5 misho 164: * @opt_data = Optional data
165: * @opt_dlen = Optional data length
1.1 misho 166: * return: NULL error or !=NULL new queued task
167: */
168: sched_task_t *
1.5 misho 169: schedWrite(sched_root_task_t * __restrict root, sched_task_func_t func, void *arg, int fd,
170: void *opt_data, size_t opt_dlen)
1.1 misho 171: {
172: sched_task_t *task;
173: void *ptr;
174:
175: if (!root || !func)
176: return NULL;
177:
178: /* get new task */
1.4 misho 179: if (!(task = _sched_useTask(root)))
180: return NULL;
1.1 misho 181:
182: memset(task, 0, sizeof(sched_task_t));
183: task->task_id = 0;
1.4 misho 184: task->task_lock = 0;
1.1 misho 185: task->task_func = func;
1.5 misho 186: TASK_TYPE(task) = taskWRITE;
187: TASK_ROOT(task) = root;
1.1 misho 188:
189: TASK_ARG(task) = arg;
1.2 misho 190: TASK_FD(task) = fd;
1.1 misho 191:
1.5 misho 192: TASK_DATA(task) = opt_data;
193: TASK_DATLEN(task) = opt_dlen;
194:
1.1 misho 195: if (root->root_hooks.hook_add.write)
196: ptr = root->root_hooks.hook_add.write(task, NULL);
197: else
198: ptr = NULL;
199:
1.5 misho 200: if (!ptr) {
201: #ifdef HAVE_LIBPTHREAD
202: pthread_mutex_lock(&root->root_mtx[taskWRITE]);
203: #endif
1.1 misho 204: TAILQ_INSERT_TAIL(&root->root_write, task, task_node);
1.5 misho 205: #ifdef HAVE_LIBPTHREAD
206: pthread_mutex_unlock(&root->root_mtx[taskWRITE]);
207: #endif
208: } else
1.4 misho 209: task = _sched_unuseTask(task);
1.1 misho 210:
211: return task;
212: }
213:
214: /*
1.7.4.1 ! misho 215: * schedAlarm() - Add ALARM task to scheduler queue
! 216: *
! 217: * @root = root task
! 218: * @func = task execution function
! 219: * @arg = 1st func argument
! 220: * @ts = timeout argument structure
! 221: * @opt_data = Optional data
! 222: * @opt_dlen = Optional data length
! 223: * return: NULL error or !=NULL new queued task
! 224: */
! 225: sched_task_t *
! 226: schedAlarm(sched_root_task_t * __restrict root, sched_task_func_t func, void *arg, struct timespec ts,
! 227: void *opt_data, size_t opt_dlen)
! 228: {
! 229: sched_task_t *task;
! 230: void *ptr;
! 231:
! 232: if (!root || !func)
! 233: return NULL;
! 234:
! 235: /* get new task */
! 236: if (!(task = _sched_useTask(root)))
! 237: return NULL;
! 238:
! 239: memset(task, 0, sizeof(sched_task_t));
! 240: task->task_id = 0;
! 241: task->task_lock = 0;
! 242: task->task_func = func;
! 243: TASK_TYPE(task) = taskALARM;
! 244: TASK_ROOT(task) = root;
! 245:
! 246: TASK_ARG(task) = arg;
! 247: TASK_TS(task) = ts;
! 248:
! 249: TASK_DATA(task) = opt_data;
! 250: TASK_DATLEN(task) = opt_dlen;
! 251:
! 252: if (root->root_hooks.hook_add.alarm)
! 253: ptr = root->root_hooks.hook_add.alarm(task, NULL);
! 254: else
! 255: ptr = NULL;
! 256:
! 257: if (!ptr) {
! 258: #ifdef HAVE_LIBPTHREAD
! 259: pthread_mutex_lock(&root->root_mtx[taskALARM]);
! 260: #endif
! 261: TAILQ_INSERT_TAIL(&root->root_alarm, task, task_node);
! 262: #ifdef HAVE_LIBPTHREAD
! 263: pthread_mutex_unlock(&root->root_mtx[taskALARM]);
! 264: #endif
! 265: } else
! 266: task = _sched_unuseTask(task);
! 267:
! 268: return task;
! 269: }
! 270:
! 271: /*
1.1 misho 272: * schedTimer() - Add TIMER task to scheduler queue
1.6 misho 273: *
1.1 misho 274: * @root = root task
275: * @func = task execution function
276: * @arg = 1st func argument
1.5 misho 277: * @ts = timeout argument structure
278: * @opt_data = Optional data
279: * @opt_dlen = Optional data length
1.1 misho 280: * return: NULL error or !=NULL new queued task
281: */
282: sched_task_t *
1.5 misho 283: schedTimer(sched_root_task_t * __restrict root, sched_task_func_t func, void *arg, struct timespec ts,
284: void *opt_data, size_t opt_dlen)
1.1 misho 285: {
286: sched_task_t *task, *t = NULL;
287: void *ptr;
1.5 misho 288: struct timespec now;
1.1 misho 289:
290: if (!root || !func)
291: return NULL;
292:
293: /* get new task */
1.4 misho 294: if (!(task = _sched_useTask(root)))
295: return NULL;
1.1 misho 296:
297: memset(task, 0, sizeof(sched_task_t));
298: task->task_id = 0;
1.4 misho 299: task->task_lock = 0;
1.1 misho 300: task->task_func = func;
1.5 misho 301: TASK_TYPE(task) = taskTIMER;
302: TASK_ROOT(task) = root;
1.1 misho 303:
304: TASK_ARG(task) = arg;
305:
1.5 misho 306: TASK_DATA(task) = opt_data;
307: TASK_DATLEN(task) = opt_dlen;
308:
1.1 misho 309: /* calculate timeval structure */
1.5 misho 310: clock_gettime(CLOCK_MONOTONIC, &now);
311: now.tv_sec += ts.tv_sec;
312: now.tv_nsec += ts.tv_nsec;
313: if (now.tv_nsec >= 1000000000L) {
1.1 misho 314: now.tv_sec++;
1.5 misho 315: now.tv_nsec -= 1000000000L;
316: } else if (now.tv_nsec < 0) {
1.1 misho 317: now.tv_sec--;
1.5 misho 318: now.tv_nsec += 1000000000L;
1.1 misho 319: }
1.5 misho 320: TASK_TS(task) = now;
1.1 misho 321:
322: if (root->root_hooks.hook_add.timer)
323: ptr = root->root_hooks.hook_add.timer(task, NULL);
324: else
325: ptr = NULL;
326:
327: if (!ptr) {
1.5 misho 328: #ifdef HAVE_LIBPTHREAD
329: pthread_mutex_lock(&root->root_mtx[taskTIMER]);
330: #endif
1.1 misho 331: #ifdef TIMER_WITHOUT_SORT
332: TAILQ_INSERT_TAIL(&root->root_timer, task, task_node);
333: #else
334: TAILQ_FOREACH(t, &root->root_timer, task_node)
1.5 misho 335: if (sched_timespeccmp(&TASK_TS(task), &TASK_TS(t), -) < 1)
1.1 misho 336: break;
337: if (!t)
338: TAILQ_INSERT_TAIL(&root->root_timer, task, task_node);
339: else
340: TAILQ_INSERT_BEFORE(t, task, task_node);
341: #endif
1.5 misho 342: #ifdef HAVE_LIBPTHREAD
343: pthread_mutex_unlock(&root->root_mtx[taskTIMER]);
344: #endif
1.4 misho 345: } else
346: task = _sched_unuseTask(task);
1.1 misho 347:
348: return task;
349: }
350:
351: /*
352: * schedEvent() - Add EVENT task to scheduler queue
1.6 misho 353: *
1.1 misho 354: * @root = root task
355: * @func = task execution function
356: * @arg = 1st func argument
1.2 misho 357: * @val = additional func argument
1.5 misho 358: * @opt_data = Optional data
359: * @opt_dlen = Optional data length
1.1 misho 360: * return: NULL error or !=NULL new queued task
361: */
362: sched_task_t *
1.5 misho 363: schedEvent(sched_root_task_t * __restrict root, sched_task_func_t func, void *arg, u_long val,
364: void *opt_data, size_t opt_dlen)
1.1 misho 365: {
366: sched_task_t *task;
367: void *ptr;
368:
369: if (!root || !func)
370: return NULL;
371:
372: /* get new task */
1.4 misho 373: if (!(task = _sched_useTask(root)))
374: return NULL;
1.1 misho 375:
376: memset(task, 0, sizeof(sched_task_t));
377: task->task_id = 0;
1.4 misho 378: task->task_lock = 0;
1.1 misho 379: task->task_func = func;
1.5 misho 380: TASK_TYPE(task) = taskEVENT;
381: TASK_ROOT(task) = root;
1.1 misho 382:
383: TASK_ARG(task) = arg;
1.2 misho 384: TASK_VAL(task) = val;
1.1 misho 385:
1.5 misho 386: TASK_DATA(task) = opt_data;
387: TASK_DATLEN(task) = opt_dlen;
388:
1.1 misho 389: if (root->root_hooks.hook_add.event)
390: ptr = root->root_hooks.hook_add.event(task, NULL);
391: else
392: ptr = NULL;
393:
1.5 misho 394: if (!ptr) {
395: #ifdef HAVE_LIBPTHREAD
396: pthread_mutex_lock(&root->root_mtx[taskEVENT]);
397: #endif
1.1 misho 398: TAILQ_INSERT_TAIL(&root->root_event, task, task_node);
1.5 misho 399: #ifdef HAVE_LIBPTHREAD
400: pthread_mutex_unlock(&root->root_mtx[taskEVENT]);
401: #endif
402: } else
1.4 misho 403: task = _sched_unuseTask(task);
1.1 misho 404:
405: return task;
406: }
407:
408:
409: /*
410: * schedEventLo() - Add EVENT_Lo task to scheduler queue
1.6 misho 411: *
1.1 misho 412: * @root = root task
413: * @func = task execution function
414: * @arg = 1st func argument
1.2 misho 415: * @val = additional func argument
1.5 misho 416: * @opt_data = Optional data
417: * @opt_dlen = Optional data length
1.1 misho 418: * return: NULL error or !=NULL new queued task
419: */
420: sched_task_t *
1.5 misho 421: schedEventLo(sched_root_task_t * __restrict root, sched_task_func_t func, void *arg, u_long val,
422: void *opt_data, size_t opt_dlen)
1.1 misho 423: {
424: sched_task_t *task;
425: void *ptr;
426:
427: if (!root || !func)
428: return NULL;
429:
430: /* get new task */
1.4 misho 431: if (!(task = _sched_useTask(root)))
432: return NULL;
1.1 misho 433:
434: memset(task, 0, sizeof(sched_task_t));
435: task->task_id = 0;
1.4 misho 436: task->task_lock = 0;
1.1 misho 437: task->task_func = func;
1.5 misho 438: TASK_TYPE(task) = taskEVENT;
439: TASK_ROOT(task) = root;
1.1 misho 440:
441: TASK_ARG(task) = arg;
1.2 misho 442: TASK_VAL(task) = val;
1.1 misho 443:
1.5 misho 444: TASK_DATA(task) = opt_data;
445: TASK_DATLEN(task) = opt_dlen;
446:
1.1 misho 447: if (root->root_hooks.hook_add.eventlo)
448: ptr = root->root_hooks.hook_add.eventlo(task, NULL);
449: else
450: ptr = NULL;
451:
1.5 misho 452: if (!ptr) {
453: #ifdef HAVE_LIBPTHREAD
454: pthread_mutex_lock(&root->root_mtx[taskEVENTLO]);
455: #endif
1.1 misho 456: TAILQ_INSERT_TAIL(&root->root_eventlo, task, task_node);
1.5 misho 457: #ifdef HAVE_LIBPTHREAD
458: pthread_mutex_unlock(&root->root_mtx[taskEVENTLO]);
459: #endif
460: } else
1.4 misho 461: task = _sched_unuseTask(task);
1.1 misho 462:
463: return task;
464: }
465:
466: /*
467: * schedCallOnce() - Call once from scheduler
1.6 misho 468: *
1.1 misho 469: * @root = root task
470: * @func = task execution function
471: * @arg = 1st func argument
1.2 misho 472: * @val = additional func argument
1.5 misho 473: * @opt_data = Optional data
474: * @opt_dlen = Optional data length
1.2 misho 475: * return: return value from called func
1.1 misho 476: */
477: sched_task_t *
1.5 misho 478: schedCallOnce(sched_root_task_t * __restrict root, sched_task_func_t func, void *arg, u_long val,
479: void *opt_data, size_t opt_dlen)
1.1 misho 480: {
481: sched_task_t *task;
1.2 misho 482: void *ret;
1.1 misho 483:
484: if (!root || !func)
485: return NULL;
486:
487: /* get new task */
1.4 misho 488: if (!(task = _sched_useTask(root)))
489: return NULL;
1.1 misho 490:
491: memset(task, 0, sizeof(sched_task_t));
492: task->task_id = 0;
1.4 misho 493: task->task_lock = 0;
1.1 misho 494: task->task_func = func;
1.5 misho 495: TASK_TYPE(task) = taskEVENT;
496: TASK_ROOT(task) = root;
1.1 misho 497:
498: TASK_ARG(task) = arg;
1.2 misho 499: TASK_VAL(task) = val;
1.1 misho 500:
1.5 misho 501: TASK_DATA(task) = opt_data;
502: TASK_DATLEN(task) = opt_dlen;
503:
1.2 misho 504: ret = schedCall(task);
1.1 misho 505:
1.4 misho 506: _sched_unuseTask(task);
1.2 misho 507: return ret;
1.1 misho 508: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>