1: /*************************************************************************
2: * (C) 2011 AITNET ltd - Sofia/Bulgaria - <misho@aitbg.com>
3: * by Michael Pounov <misho@openbsd-bg.org>
4: *
5: * $Author: misho $
6: * $Id: tasks.c,v 1.4 2012/01/08 00:51:17 misho Exp $
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:
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)) {
58: TAILQ_REMOVE(&root->root_unuse, task, task_node);
59: break;
60: }
61: }
62:
63: if (!task) {
64: task = malloc(sizeof(sched_task_t));
65: if (!task) {
66: LOGERR;
67: return NULL;
68: }
69: }
70:
71: return task;
72: }
73:
74: inline sched_task_t *
75: _sched_unuseTask(sched_task_t * __restrict task)
76: {
77: TASK_UNLOCK(task);
78: task->task_type = taskUNUSE;
79: TAILQ_INSERT_TAIL(&task->task_root->root_unuse, task, task_node);
80: task = NULL;
81:
82: return task;
83: }
84:
85: #pragma GCC visibility pop
86:
87:
88: /*
89: * schedRead() - Add READ I/O task to scheduler queue
90: * @root = root task
91: * @func = task execution function
92: * @arg = 1st func argument
93: * @fd = fd handle
94: * return: NULL error or !=NULL new queued task
95: */
96: sched_task_t *
97: schedRead(sched_root_task_t * __restrict root, sched_task_func_t func, void *arg, int fd)
98: {
99: sched_task_t *task;
100: void *ptr;
101:
102: if (!root || !func)
103: return NULL;
104:
105: /* get new task */
106: if (!(task = _sched_useTask(root)))
107: return NULL;
108:
109: memset(task, 0, sizeof(sched_task_t));
110: task->task_id = 0;
111: task->task_lock = 0;
112: task->task_type = taskREAD;
113: task->task_root = root;
114: task->task_func = func;
115:
116: TASK_ARG(task) = arg;
117: TASK_FD(task) = fd;
118:
119: if (root->root_hooks.hook_add.read)
120: ptr = root->root_hooks.hook_add.read(task, NULL);
121: else
122: ptr = NULL;
123:
124: if (!ptr)
125: TAILQ_INSERT_TAIL(&root->root_read, task, task_node);
126: else
127: task = _sched_unuseTask(task);
128:
129: return task;
130: }
131:
132: /*
133: * schedWrite() - Add WRITE I/O task to scheduler queue
134: * @root = root task
135: * @func = task execution function
136: * @arg = 1st func argument
137: * @fd = fd handle
138: * return: NULL error or !=NULL new queued task
139: */
140: sched_task_t *
141: schedWrite(sched_root_task_t * __restrict root, sched_task_func_t func, void *arg, int fd)
142: {
143: sched_task_t *task;
144: void *ptr;
145:
146: if (!root || !func)
147: return NULL;
148:
149: /* get new task */
150: if (!(task = _sched_useTask(root)))
151: return NULL;
152:
153: memset(task, 0, sizeof(sched_task_t));
154: task->task_id = 0;
155: task->task_lock = 0;
156: task->task_type = taskWRITE;
157: task->task_root = root;
158: task->task_func = func;
159:
160: TASK_ARG(task) = arg;
161: TASK_FD(task) = fd;
162:
163: if (root->root_hooks.hook_add.write)
164: ptr = root->root_hooks.hook_add.write(task, NULL);
165: else
166: ptr = NULL;
167:
168: if (!ptr)
169: TAILQ_INSERT_TAIL(&root->root_write, task, task_node);
170: else
171: task = _sched_unuseTask(task);
172:
173: return task;
174: }
175:
176: /*
177: * schedTimer() - Add TIMER task to scheduler queue
178: * @root = root task
179: * @func = task execution function
180: * @arg = 1st func argument
181: * @tv = timeout argument structure
182: * return: NULL error or !=NULL new queued task
183: */
184: sched_task_t *
185: schedTimer(sched_root_task_t * __restrict root, sched_task_func_t func, void *arg, struct timeval tv)
186: {
187: sched_task_t *task, *t = NULL;
188: void *ptr;
189: struct timeval now;
190: struct timespec nw;
191:
192: if (!root || !func)
193: return NULL;
194:
195: /* get new task */
196: if (!(task = _sched_useTask(root)))
197: return NULL;
198:
199: memset(task, 0, sizeof(sched_task_t));
200: task->task_id = 0;
201: task->task_lock = 0;
202: task->task_type = taskTIMER;
203: task->task_root = root;
204: task->task_func = func;
205:
206: TASK_ARG(task) = arg;
207:
208: /* calculate timeval structure */
209: clock_gettime(CLOCK_MONOTONIC, &nw);
210: now.tv_sec = nw.tv_sec + tv.tv_sec;
211: now.tv_usec = nw.tv_nsec / 1000 + tv.tv_usec;
212: if (now.tv_usec >= 1000000) {
213: now.tv_sec++;
214: now.tv_usec -= 1000000;
215: } else if (now.tv_usec < 0) {
216: now.tv_sec--;
217: now.tv_usec += 1000000;
218: }
219: TASK_TV(task) = now;
220:
221: if (root->root_hooks.hook_add.timer)
222: ptr = root->root_hooks.hook_add.timer(task, NULL);
223: else
224: ptr = NULL;
225:
226: if (!ptr) {
227: #ifdef TIMER_WITHOUT_SORT
228: TAILQ_INSERT_TAIL(&root->root_timer, task, task_node);
229: #else
230: TAILQ_FOREACH(t, &root->root_timer, task_node)
231: if (timercmp(&TASK_TV(task), &TASK_TV(t), -) < 1)
232: break;
233: if (!t)
234: TAILQ_INSERT_TAIL(&root->root_timer, task, task_node);
235: else
236: TAILQ_INSERT_BEFORE(t, task, task_node);
237: #endif
238: } else
239: task = _sched_unuseTask(task);
240:
241: return task;
242: }
243:
244: /*
245: * schedEvent() - Add EVENT task to scheduler queue
246: * @root = root task
247: * @func = task execution function
248: * @arg = 1st func argument
249: * @val = additional func argument
250: * return: NULL error or !=NULL new queued task
251: */
252: sched_task_t *
253: schedEvent(sched_root_task_t * __restrict root, sched_task_func_t func, void *arg, u_long val)
254: {
255: sched_task_t *task;
256: void *ptr;
257:
258: if (!root || !func)
259: return NULL;
260:
261: /* get new task */
262: if (!(task = _sched_useTask(root)))
263: return NULL;
264:
265: memset(task, 0, sizeof(sched_task_t));
266: task->task_id = 0;
267: task->task_lock = 0;
268: task->task_type = taskEVENT;
269: task->task_root = root;
270: task->task_func = func;
271:
272: TASK_ARG(task) = arg;
273: TASK_VAL(task) = val;
274:
275: if (root->root_hooks.hook_add.event)
276: ptr = root->root_hooks.hook_add.event(task, NULL);
277: else
278: ptr = NULL;
279:
280: if (!ptr)
281: TAILQ_INSERT_TAIL(&root->root_event, task, task_node);
282: else
283: task = _sched_unuseTask(task);
284:
285: return task;
286: }
287:
288:
289: /*
290: * schedEventLo() - Add EVENT_Lo task to scheduler queue
291: * @root = root task
292: * @func = task execution function
293: * @arg = 1st func argument
294: * @val = additional func argument
295: * return: NULL error or !=NULL new queued task
296: */
297: sched_task_t *
298: schedEventLo(sched_root_task_t * __restrict root, sched_task_func_t func, void *arg, u_long val)
299: {
300: sched_task_t *task;
301: void *ptr;
302:
303: if (!root || !func)
304: return NULL;
305:
306: /* get new task */
307: if (!(task = _sched_useTask(root)))
308: return NULL;
309:
310: memset(task, 0, sizeof(sched_task_t));
311: task->task_id = 0;
312: task->task_lock = 0;
313: task->task_type = taskEVENT;
314: task->task_root = root;
315: task->task_func = func;
316:
317: TASK_ARG(task) = arg;
318: TASK_VAL(task) = val;
319:
320: if (root->root_hooks.hook_add.eventlo)
321: ptr = root->root_hooks.hook_add.eventlo(task, NULL);
322: else
323: ptr = NULL;
324:
325: if (!ptr)
326: TAILQ_INSERT_TAIL(&root->root_eventlo, task, task_node);
327: else
328: task = _sched_unuseTask(task);
329:
330: return task;
331: }
332:
333: /*
334: * schedCallOnce() - Call once from scheduler
335: * @root = root task
336: * @func = task execution function
337: * @arg = 1st func argument
338: * @val = additional func argument
339: * return: return value from called func
340: */
341: sched_task_t *
342: schedCallOnce(sched_root_task_t * __restrict root, sched_task_func_t func, void *arg, u_long val)
343: {
344: sched_task_t *task;
345: void *ret;
346:
347: if (!root || !func)
348: return NULL;
349:
350: /* get new task */
351: if (!(task = _sched_useTask(root)))
352: return NULL;
353:
354: memset(task, 0, sizeof(sched_task_t));
355: task->task_id = 0;
356: task->task_lock = 0;
357: task->task_type = taskEVENT;
358: task->task_root = root;
359: task->task_func = func;
360:
361: TASK_ARG(task) = arg;
362: TASK_VAL(task) = val;
363:
364: ret = schedCall(task);
365:
366: _sched_unuseTask(task);
367: return ret;
368: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>