Annotation of libaitsched/src/tasks.c, revision 1.4.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.4.2.3 ! misho 6: * $Id: tasks.c,v 1.4.2.2 2012/01/23 15:56:23 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:
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: {
54: sched_task_t *task;
55:
56: TAILQ_FOREACH(task, &root->root_unuse, task_node) {
57: if (!TASK_ISLOCKED(task)) {
1.4.2.1 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.4.2.1 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.4.2.1 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.1 misho 102: * @root = root task
103: * @func = task execution function
104: * @arg = 1st func argument
1.2 misho 105: * @fd = fd handle
1.4.2.2 misho 106: * @opt_data = Optional data
107: * @opt_dlen = Optional data length
1.1 misho 108: * return: NULL error or !=NULL new queued task
109: */
110: sched_task_t *
1.4.2.2 misho 111: schedRead(sched_root_task_t * __restrict root, sched_task_func_t func, void *arg, int fd,
112: void *opt_data, size_t opt_dlen)
1.1 misho 113: {
114: sched_task_t *task;
115: void *ptr;
116:
117: if (!root || !func)
118: return NULL;
119:
120: /* get new task */
1.4 misho 121: if (!(task = _sched_useTask(root)))
122: return NULL;
1.1 misho 123:
124: memset(task, 0, sizeof(sched_task_t));
125: task->task_id = 0;
1.4 misho 126: task->task_lock = 0;
1.1 misho 127: task->task_func = func;
1.4.2.1 misho 128: TASK_TYPE(task) = taskREAD;
129: TASK_ROOT(task) = root;
1.1 misho 130:
131: TASK_ARG(task) = arg;
1.2 misho 132: TASK_FD(task) = fd;
1.1 misho 133:
1.4.2.2 misho 134: TASK_DATA(task) = opt_data;
135: TASK_DATLEN(task) = opt_dlen;
136:
1.1 misho 137: if (root->root_hooks.hook_add.read)
138: ptr = root->root_hooks.hook_add.read(task, NULL);
139: else
140: ptr = NULL;
141:
1.4.2.1 misho 142: if (!ptr) {
143: #ifdef HAVE_LIBPTHREAD
144: pthread_mutex_lock(&root->root_mtx[taskREAD]);
145: #endif
1.1 misho 146: TAILQ_INSERT_TAIL(&root->root_read, task, task_node);
1.4.2.1 misho 147: #ifdef HAVE_LIBPTHREAD
148: pthread_mutex_unlock(&root->root_mtx[taskREAD]);
149: #endif
150: } else
1.4 misho 151: task = _sched_unuseTask(task);
1.1 misho 152:
153: return task;
154: }
155:
156: /*
1.2 misho 157: * schedWrite() - Add WRITE I/O task to scheduler queue
1.1 misho 158: * @root = root task
159: * @func = task execution function
160: * @arg = 1st func argument
1.2 misho 161: * @fd = fd handle
1.4.2.2 misho 162: * @opt_data = Optional data
163: * @opt_dlen = Optional data length
1.1 misho 164: * return: NULL error or !=NULL new queued task
165: */
166: sched_task_t *
1.4.2.2 misho 167: schedWrite(sched_root_task_t * __restrict root, sched_task_func_t func, void *arg, int fd,
168: void *opt_data, size_t opt_dlen)
1.1 misho 169: {
170: sched_task_t *task;
171: void *ptr;
172:
173: if (!root || !func)
174: return NULL;
175:
176: /* get new task */
1.4 misho 177: if (!(task = _sched_useTask(root)))
178: return NULL;
1.1 misho 179:
180: memset(task, 0, sizeof(sched_task_t));
181: task->task_id = 0;
1.4 misho 182: task->task_lock = 0;
1.1 misho 183: task->task_func = func;
1.4.2.1 misho 184: TASK_TYPE(task) = taskWRITE;
185: TASK_ROOT(task) = root;
1.1 misho 186:
187: TASK_ARG(task) = arg;
1.2 misho 188: TASK_FD(task) = fd;
1.1 misho 189:
1.4.2.2 misho 190: TASK_DATA(task) = opt_data;
191: TASK_DATLEN(task) = opt_dlen;
192:
1.1 misho 193: if (root->root_hooks.hook_add.write)
194: ptr = root->root_hooks.hook_add.write(task, NULL);
195: else
196: ptr = NULL;
197:
1.4.2.1 misho 198: if (!ptr) {
199: #ifdef HAVE_LIBPTHREAD
200: pthread_mutex_lock(&root->root_mtx[taskWRITE]);
201: #endif
1.1 misho 202: TAILQ_INSERT_TAIL(&root->root_write, task, task_node);
1.4.2.1 misho 203: #ifdef HAVE_LIBPTHREAD
204: pthread_mutex_unlock(&root->root_mtx[taskWRITE]);
205: #endif
206: } else
1.4 misho 207: task = _sched_unuseTask(task);
1.1 misho 208:
209: return task;
210: }
211:
212: /*
213: * schedTimer() - Add TIMER task to scheduler queue
214: * @root = root task
215: * @func = task execution function
216: * @arg = 1st func argument
1.4.2.3 ! misho 217: * @ts = timeout argument structure
1.4.2.2 misho 218: * @opt_data = Optional data
219: * @opt_dlen = Optional data length
1.1 misho 220: * return: NULL error or !=NULL new queued task
221: */
222: sched_task_t *
1.4.2.3 ! misho 223: schedTimer(sched_root_task_t * __restrict root, sched_task_func_t func, void *arg, struct timespec ts,
1.4.2.2 misho 224: void *opt_data, size_t opt_dlen)
1.1 misho 225: {
226: sched_task_t *task, *t = NULL;
227: void *ptr;
1.4.2.3 ! misho 228: struct timespec now;
1.1 misho 229:
230: if (!root || !func)
231: return NULL;
232:
233: /* get new task */
1.4 misho 234: if (!(task = _sched_useTask(root)))
235: return NULL;
1.1 misho 236:
237: memset(task, 0, sizeof(sched_task_t));
238: task->task_id = 0;
1.4 misho 239: task->task_lock = 0;
1.1 misho 240: task->task_func = func;
1.4.2.1 misho 241: TASK_TYPE(task) = taskTIMER;
242: TASK_ROOT(task) = root;
1.1 misho 243:
244: TASK_ARG(task) = arg;
245:
1.4.2.2 misho 246: TASK_DATA(task) = opt_data;
247: TASK_DATLEN(task) = opt_dlen;
248:
1.1 misho 249: /* calculate timeval structure */
1.4.2.3 ! misho 250: clock_gettime(CLOCK_MONOTONIC, &now);
! 251: now.tv_sec += ts.tv_sec;
! 252: now.tv_nsec += ts.tv_nsec;
! 253: if (now.tv_nsec >= 1000000000) {
1.1 misho 254: now.tv_sec++;
1.4.2.3 ! misho 255: now.tv_nsec -= 1000000000;
! 256: } else if (now.tv_nsec < 0) {
1.1 misho 257: now.tv_sec--;
1.4.2.3 ! misho 258: now.tv_nsec += 1000000000;
1.1 misho 259: }
1.4.2.3 ! misho 260: TASK_TS(task) = now;
1.1 misho 261:
262: if (root->root_hooks.hook_add.timer)
263: ptr = root->root_hooks.hook_add.timer(task, NULL);
264: else
265: ptr = NULL;
266:
267: if (!ptr) {
1.4.2.1 misho 268: #ifdef HAVE_LIBPTHREAD
269: pthread_mutex_lock(&root->root_mtx[taskTIMER]);
270: #endif
1.1 misho 271: #ifdef TIMER_WITHOUT_SORT
272: TAILQ_INSERT_TAIL(&root->root_timer, task, task_node);
273: #else
274: TAILQ_FOREACH(t, &root->root_timer, task_node)
1.4.2.3 ! misho 275: if (timespeccmp(&TASK_TS(task), &TASK_TS(t), -) < 1)
1.1 misho 276: break;
277: if (!t)
278: TAILQ_INSERT_TAIL(&root->root_timer, task, task_node);
279: else
280: TAILQ_INSERT_BEFORE(t, task, task_node);
281: #endif
1.4.2.1 misho 282: #ifdef HAVE_LIBPTHREAD
283: pthread_mutex_unlock(&root->root_mtx[taskTIMER]);
284: #endif
1.4 misho 285: } else
286: task = _sched_unuseTask(task);
1.1 misho 287:
288: return task;
289: }
290:
291: /*
292: * schedEvent() - Add EVENT task to scheduler queue
293: * @root = root task
294: * @func = task execution function
295: * @arg = 1st func argument
1.2 misho 296: * @val = additional func argument
1.4.2.2 misho 297: * @opt_data = Optional data
298: * @opt_dlen = Optional data length
1.1 misho 299: * return: NULL error or !=NULL new queued task
300: */
301: sched_task_t *
1.4.2.2 misho 302: schedEvent(sched_root_task_t * __restrict root, sched_task_func_t func, void *arg, u_long val,
303: void *opt_data, size_t opt_dlen)
1.1 misho 304: {
305: sched_task_t *task;
306: void *ptr;
307:
308: if (!root || !func)
309: return NULL;
310:
311: /* get new task */
1.4 misho 312: if (!(task = _sched_useTask(root)))
313: return NULL;
1.1 misho 314:
315: memset(task, 0, sizeof(sched_task_t));
316: task->task_id = 0;
1.4 misho 317: task->task_lock = 0;
1.1 misho 318: task->task_func = func;
1.4.2.1 misho 319: TASK_TYPE(task) = taskEVENT;
320: TASK_ROOT(task) = root;
1.1 misho 321:
322: TASK_ARG(task) = arg;
1.2 misho 323: TASK_VAL(task) = val;
1.1 misho 324:
1.4.2.2 misho 325: TASK_DATA(task) = opt_data;
326: TASK_DATLEN(task) = opt_dlen;
327:
1.1 misho 328: if (root->root_hooks.hook_add.event)
329: ptr = root->root_hooks.hook_add.event(task, NULL);
330: else
331: ptr = NULL;
332:
1.4.2.1 misho 333: if (!ptr) {
334: #ifdef HAVE_LIBPTHREAD
335: pthread_mutex_lock(&root->root_mtx[taskEVENT]);
336: #endif
1.1 misho 337: TAILQ_INSERT_TAIL(&root->root_event, task, task_node);
1.4.2.1 misho 338: #ifdef HAVE_LIBPTHREAD
339: pthread_mutex_unlock(&root->root_mtx[taskEVENT]);
340: #endif
341: } else
1.4 misho 342: task = _sched_unuseTask(task);
1.1 misho 343:
344: return task;
345: }
346:
347:
348: /*
349: * schedEventLo() - Add EVENT_Lo task to scheduler queue
350: * @root = root task
351: * @func = task execution function
352: * @arg = 1st func argument
1.2 misho 353: * @val = additional func argument
1.4.2.2 misho 354: * @opt_data = Optional data
355: * @opt_dlen = Optional data length
1.1 misho 356: * return: NULL error or !=NULL new queued task
357: */
358: sched_task_t *
1.4.2.2 misho 359: schedEventLo(sched_root_task_t * __restrict root, sched_task_func_t func, void *arg, u_long val,
360: void *opt_data, size_t opt_dlen)
1.1 misho 361: {
362: sched_task_t *task;
363: void *ptr;
364:
365: if (!root || !func)
366: return NULL;
367:
368: /* get new task */
1.4 misho 369: if (!(task = _sched_useTask(root)))
370: return NULL;
1.1 misho 371:
372: memset(task, 0, sizeof(sched_task_t));
373: task->task_id = 0;
1.4 misho 374: task->task_lock = 0;
1.1 misho 375: task->task_func = func;
1.4.2.1 misho 376: TASK_TYPE(task) = taskEVENT;
377: TASK_ROOT(task) = root;
1.1 misho 378:
379: TASK_ARG(task) = arg;
1.2 misho 380: TASK_VAL(task) = val;
1.1 misho 381:
1.4.2.2 misho 382: TASK_DATA(task) = opt_data;
383: TASK_DATLEN(task) = opt_dlen;
384:
1.1 misho 385: if (root->root_hooks.hook_add.eventlo)
386: ptr = root->root_hooks.hook_add.eventlo(task, NULL);
387: else
388: ptr = NULL;
389:
1.4.2.1 misho 390: if (!ptr) {
391: #ifdef HAVE_LIBPTHREAD
392: pthread_mutex_lock(&root->root_mtx[taskEVENTLO]);
393: #endif
1.1 misho 394: TAILQ_INSERT_TAIL(&root->root_eventlo, task, task_node);
1.4.2.1 misho 395: #ifdef HAVE_LIBPTHREAD
396: pthread_mutex_unlock(&root->root_mtx[taskEVENTLO]);
397: #endif
398: } else
1.4 misho 399: task = _sched_unuseTask(task);
1.1 misho 400:
401: return task;
402: }
403:
404: /*
405: * schedCallOnce() - Call once from scheduler
406: * @root = root task
407: * @func = task execution function
408: * @arg = 1st func argument
1.2 misho 409: * @val = additional func argument
1.4.2.2 misho 410: * @opt_data = Optional data
411: * @opt_dlen = Optional data length
1.2 misho 412: * return: return value from called func
1.1 misho 413: */
414: sched_task_t *
1.4.2.2 misho 415: schedCallOnce(sched_root_task_t * __restrict root, sched_task_func_t func, void *arg, u_long val,
416: void *opt_data, size_t opt_dlen)
1.1 misho 417: {
418: sched_task_t *task;
1.2 misho 419: void *ret;
1.1 misho 420:
421: if (!root || !func)
422: return NULL;
423:
424: /* get new task */
1.4 misho 425: if (!(task = _sched_useTask(root)))
426: return NULL;
1.1 misho 427:
428: memset(task, 0, sizeof(sched_task_t));
429: task->task_id = 0;
1.4 misho 430: task->task_lock = 0;
1.1 misho 431: task->task_func = func;
1.4.2.1 misho 432: TASK_TYPE(task) = taskEVENT;
433: TASK_ROOT(task) = root;
1.1 misho 434:
435: TASK_ARG(task) = arg;
1.2 misho 436: TASK_VAL(task) = val;
1.1 misho 437:
1.4.2.2 misho 438: TASK_DATA(task) = opt_data;
439: TASK_DATLEN(task) = opt_dlen;
440:
1.2 misho 441: ret = schedCall(task);
1.1 misho 442:
1.4 misho 443: _sched_unuseTask(task);
1.2 misho 444: return ret;
1.1 misho 445: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>