Annotation of libaitsched/src/tasks.c, revision 1.4.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.4.2.2 ! misho 6: * $Id: tasks.c,v 1.4.2.1 2012/01/08 03:50:11 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.3 misho 217: * @tv = 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.2 ! misho 223: schedTimer(sched_root_task_t * __restrict root, sched_task_func_t func, void *arg, struct timeval tv,
! 224: void *opt_data, size_t opt_dlen)
1.1 misho 225: {
226: sched_task_t *task, *t = NULL;
227: void *ptr;
228: struct timeval now;
229: struct timespec nw;
230:
231: if (!root || !func)
232: return NULL;
233:
234: /* get new task */
1.4 misho 235: if (!(task = _sched_useTask(root)))
236: return NULL;
1.1 misho 237:
238: memset(task, 0, sizeof(sched_task_t));
239: task->task_id = 0;
1.4 misho 240: task->task_lock = 0;
1.1 misho 241: task->task_func = func;
1.4.2.1 misho 242: TASK_TYPE(task) = taskTIMER;
243: TASK_ROOT(task) = root;
1.1 misho 244:
245: TASK_ARG(task) = arg;
246:
1.4.2.2 ! misho 247: TASK_DATA(task) = opt_data;
! 248: TASK_DATLEN(task) = opt_dlen;
! 249:
1.1 misho 250: /* calculate timeval structure */
251: clock_gettime(CLOCK_MONOTONIC, &nw);
1.3 misho 252: now.tv_sec = nw.tv_sec + tv.tv_sec;
253: now.tv_usec = nw.tv_nsec / 1000 + tv.tv_usec;
1.1 misho 254: if (now.tv_usec >= 1000000) {
255: now.tv_sec++;
256: now.tv_usec -= 1000000;
257: } else if (now.tv_usec < 0) {
258: now.tv_sec--;
259: now.tv_usec += 1000000;
260: }
261: TASK_TV(task) = now;
262:
263: if (root->root_hooks.hook_add.timer)
264: ptr = root->root_hooks.hook_add.timer(task, NULL);
265: else
266: ptr = NULL;
267:
268: if (!ptr) {
1.4.2.1 misho 269: #ifdef HAVE_LIBPTHREAD
270: pthread_mutex_lock(&root->root_mtx[taskTIMER]);
271: #endif
1.1 misho 272: #ifdef TIMER_WITHOUT_SORT
273: TAILQ_INSERT_TAIL(&root->root_timer, task, task_node);
274: #else
275: TAILQ_FOREACH(t, &root->root_timer, task_node)
276: if (timercmp(&TASK_TV(task), &TASK_TV(t), -) < 1)
277: break;
278: if (!t)
279: TAILQ_INSERT_TAIL(&root->root_timer, task, task_node);
280: else
281: TAILQ_INSERT_BEFORE(t, task, task_node);
282: #endif
1.4.2.1 misho 283: #ifdef HAVE_LIBPTHREAD
284: pthread_mutex_unlock(&root->root_mtx[taskTIMER]);
285: #endif
1.4 misho 286: } else
287: task = _sched_unuseTask(task);
1.1 misho 288:
289: return task;
290: }
291:
292: /*
293: * schedEvent() - Add EVENT task to scheduler queue
294: * @root = root task
295: * @func = task execution function
296: * @arg = 1st func argument
1.2 misho 297: * @val = additional func argument
1.4.2.2 ! misho 298: * @opt_data = Optional data
! 299: * @opt_dlen = Optional data length
1.1 misho 300: * return: NULL error or !=NULL new queued task
301: */
302: sched_task_t *
1.4.2.2 ! misho 303: schedEvent(sched_root_task_t * __restrict root, sched_task_func_t func, void *arg, u_long val,
! 304: void *opt_data, size_t opt_dlen)
1.1 misho 305: {
306: sched_task_t *task;
307: void *ptr;
308:
309: if (!root || !func)
310: return NULL;
311:
312: /* get new task */
1.4 misho 313: if (!(task = _sched_useTask(root)))
314: return NULL;
1.1 misho 315:
316: memset(task, 0, sizeof(sched_task_t));
317: task->task_id = 0;
1.4 misho 318: task->task_lock = 0;
1.1 misho 319: task->task_func = func;
1.4.2.1 misho 320: TASK_TYPE(task) = taskEVENT;
321: TASK_ROOT(task) = root;
1.1 misho 322:
323: TASK_ARG(task) = arg;
1.2 misho 324: TASK_VAL(task) = val;
1.1 misho 325:
1.4.2.2 ! misho 326: TASK_DATA(task) = opt_data;
! 327: TASK_DATLEN(task) = opt_dlen;
! 328:
1.1 misho 329: if (root->root_hooks.hook_add.event)
330: ptr = root->root_hooks.hook_add.event(task, NULL);
331: else
332: ptr = NULL;
333:
1.4.2.1 misho 334: if (!ptr) {
335: #ifdef HAVE_LIBPTHREAD
336: pthread_mutex_lock(&root->root_mtx[taskEVENT]);
337: #endif
1.1 misho 338: TAILQ_INSERT_TAIL(&root->root_event, task, task_node);
1.4.2.1 misho 339: #ifdef HAVE_LIBPTHREAD
340: pthread_mutex_unlock(&root->root_mtx[taskEVENT]);
341: #endif
342: } else
1.4 misho 343: task = _sched_unuseTask(task);
1.1 misho 344:
345: return task;
346: }
347:
348:
349: /*
350: * schedEventLo() - Add EVENT_Lo task to scheduler queue
351: * @root = root task
352: * @func = task execution function
353: * @arg = 1st func argument
1.2 misho 354: * @val = additional func argument
1.4.2.2 ! misho 355: * @opt_data = Optional data
! 356: * @opt_dlen = Optional data length
1.1 misho 357: * return: NULL error or !=NULL new queued task
358: */
359: sched_task_t *
1.4.2.2 ! misho 360: schedEventLo(sched_root_task_t * __restrict root, sched_task_func_t func, void *arg, u_long val,
! 361: void *opt_data, size_t opt_dlen)
1.1 misho 362: {
363: sched_task_t *task;
364: void *ptr;
365:
366: if (!root || !func)
367: return NULL;
368:
369: /* get new task */
1.4 misho 370: if (!(task = _sched_useTask(root)))
371: return NULL;
1.1 misho 372:
373: memset(task, 0, sizeof(sched_task_t));
374: task->task_id = 0;
1.4 misho 375: task->task_lock = 0;
1.1 misho 376: task->task_func = func;
1.4.2.1 misho 377: TASK_TYPE(task) = taskEVENT;
378: TASK_ROOT(task) = root;
1.1 misho 379:
380: TASK_ARG(task) = arg;
1.2 misho 381: TASK_VAL(task) = val;
1.1 misho 382:
1.4.2.2 ! misho 383: TASK_DATA(task) = opt_data;
! 384: TASK_DATLEN(task) = opt_dlen;
! 385:
1.1 misho 386: if (root->root_hooks.hook_add.eventlo)
387: ptr = root->root_hooks.hook_add.eventlo(task, NULL);
388: else
389: ptr = NULL;
390:
1.4.2.1 misho 391: if (!ptr) {
392: #ifdef HAVE_LIBPTHREAD
393: pthread_mutex_lock(&root->root_mtx[taskEVENTLO]);
394: #endif
1.1 misho 395: TAILQ_INSERT_TAIL(&root->root_eventlo, task, task_node);
1.4.2.1 misho 396: #ifdef HAVE_LIBPTHREAD
397: pthread_mutex_unlock(&root->root_mtx[taskEVENTLO]);
398: #endif
399: } else
1.4 misho 400: task = _sched_unuseTask(task);
1.1 misho 401:
402: return task;
403: }
404:
405: /*
406: * schedCallOnce() - Call once from scheduler
407: * @root = root task
408: * @func = task execution function
409: * @arg = 1st func argument
1.2 misho 410: * @val = additional func argument
1.4.2.2 ! misho 411: * @opt_data = Optional data
! 412: * @opt_dlen = Optional data length
1.2 misho 413: * return: return value from called func
1.1 misho 414: */
415: sched_task_t *
1.4.2.2 ! misho 416: schedCallOnce(sched_root_task_t * __restrict root, sched_task_func_t func, void *arg, u_long val,
! 417: void *opt_data, size_t opt_dlen)
1.1 misho 418: {
419: sched_task_t *task;
1.2 misho 420: void *ret;
1.1 misho 421:
422: if (!root || !func)
423: return NULL;
424:
425: /* get new task */
1.4 misho 426: if (!(task = _sched_useTask(root)))
427: return NULL;
1.1 misho 428:
429: memset(task, 0, sizeof(sched_task_t));
430: task->task_id = 0;
1.4 misho 431: task->task_lock = 0;
1.1 misho 432: task->task_func = func;
1.4.2.1 misho 433: TASK_TYPE(task) = taskEVENT;
434: TASK_ROOT(task) = root;
1.1 misho 435:
436: TASK_ARG(task) = arg;
1.2 misho 437: TASK_VAL(task) = val;
1.1 misho 438:
1.4.2.2 ! misho 439: TASK_DATA(task) = opt_data;
! 440: TASK_DATLEN(task) = opt_dlen;
! 441:
1.2 misho 442: ret = schedCall(task);
1.1 misho 443:
1.4 misho 444: _sched_unuseTask(task);
1.2 misho 445: return ret;
1.1 misho 446: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>