1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308
|
/*
* SPL - The SPL Programming Language
* Copyright (C) 2004, 2005 Clifford Wolf <clifford@clifford.at>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* mod_task.c: Simple task management library
*/
/**
* SPL Task Management Module
*
* This module provides basic functions for handling SPL tasks. SPL tasks
* may be used like threads, co-routines, or anything simmilar.
*/
#define _GNU_SOURCE
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "spl.h"
#include "compat.h"
static struct spl_code bytecode =
#include "spl_modules/mod_task.splh"
;
extern void SPL_ABI(spl_mod_task_init)(struct spl_vm *vm, struct spl_module *mod, int restore);
extern void SPL_ABI(spl_mod_task_done)(struct spl_vm *vm, struct spl_module *mod);
/**
* This function creates a new task. The 1st parameter is the name of the
* new task and the 2nd is the SPL program code for the task. The 2nd
* parameter will be compiled when executing the function, so it is a good
* idea to keep it small and move the big portion of the task logic to
* seperate functions. The third option is the context in which the task
* should be executed.
*
* If the task name is undefined, the task won't have a name attached to
* it and it won't be possible to access it later.
*
* If the context is ommitted, the task will run in the same context as
* the function which called this function.
*/
// builtin task_create(name, code, ctx)
static struct spl_node *handler_task_create(struct spl_task *t, void *d UNUSED)
{
char *name = spl_clib_get_string(t);
char *program = spl_clib_get_string(t);
struct spl_node *ctx = spl_clib_get_node(t);
struct spl_asm *as = spl_asm_create();
as->vm = t->vm;
if ( spl_compiler(as, program, "task_main", 0, 0) ) SPL_NEW_INT(1);
if ( spl_compiler(as, "task_kill();", "task_epilogue", 0, 0) ) SPL_NEW_INT(2);
struct spl_task *task = spl_task_create(t->vm, name);
if ( ctx ) {
spl_put(task->vm, task->ctx);
task->ctx = ctx;
}
spl_task_setcode(task, spl_asm_dump(as));
spl_asm_destroy(as);
task->flags |= SPL_TASK_FLAG_PAUSED;
return SPL_NEW_INT(0);
}
static struct spl_node *handler_task_kill(struct spl_task *t, void *d UNUSED)
{
char *name = spl_clib_get_string(t);
if ( !name[0] ) goto this_task;
t = t->vm->task_list;
while (t) {
if ( t->id && !strcmp(t->id, name) ) {
this_task:
t->flags |= SPL_TASK_FLAG_ZOMBIE;
return SPL_NEW_INT(0);
}
t= t->next;
}
return SPL_NEW_INT(1);
}
/**
* This functions pauses the specified task until it is woken up by
* [[task_continue()]] (or by an external event).
*
* If the task name is ommitted, the current task will be affected by
* this function.
*/
// builtin task_pause(name)
static struct spl_node *handler_task_pause(struct spl_task *t, void *d UNUSED)
{
char *name = spl_clib_get_string(t);
if ( !name[0] ) goto this_task;
t = t->vm->task_list;
while (t) {
if ( t->id && !strcmp(t->id, name) ) {
this_task:
t->flags |= SPL_TASK_FLAG_PAUSED;
t->flags &= ~SPL_TASK_FLAG_SYSTEM;
return SPL_NEW_INT(0);
}
t= t->next;
}
return SPL_NEW_INT(1);
}
/**
* This function wakes up the specified task. It also can be used to
* remove the SYSTEM flag from the current task (see [[task_system()]]).
*
* If the task name is ommitted, the current task will be affected by
* this function.
*/
// builtin task_continue(name)
static struct spl_node *handler_task_continue(struct spl_task *t, void *d UNUSED)
{
char *name = spl_clib_get_string(t);
if ( !name[0] ) goto this_task;
t = t->vm->task_list;
while (t) {
if ( t->id && !strcmp(t->id, name) ) {
this_task:
t->flags &= ~(SPL_TASK_FLAG_PAUSED|SPL_TASK_FLAG_SYSTEM);
return SPL_NEW_INT(0);
}
t= t->next;
}
return SPL_NEW_INT(1);
}
/**
* This function sets the SYSTEM flag on the specified task. That means
* that the scheduler will not schedule any other task until the system
* flag is removed again using [[task_continue()]] or the task is paused
* ([[task_pause()]]) or killed ([[task_kill()]]).
*
* If the task name is ommitted, the current task will be affected by
* this function. Usually this function is only used to manipulate the
* currently running task.
*/
// builtin task_system(name)
static struct spl_node *handler_task_system(struct spl_task *t, void *d UNUSED)
{
char *name = spl_clib_get_string(t);
if ( !name[0] ) goto this_task;
t = t->vm->task_list;
while (t) {
if ( t->id && !strcmp(t->id, name) ) {
this_task:
t->flags |= SPL_TASK_FLAG_SYSTEM;
return SPL_NEW_INT(0);
}
t= t->next;
}
return SPL_NEW_INT(1);
}
/**
* This function is used to set the PUBLIC flag on a task. This is e.g.
* needed when the task should be woken up by WebSPL when the taskname
* is encoded into the session id.
*
* If the task name is ommitted, the current task will be affected by
* this function.
*/
// builtin task_public(name)
static struct spl_node *handler_task_public(struct spl_task *t, void *d UNUSED)
{
char *name = spl_clib_get_string(t);
if ( !name[0] ) goto this_task;
t = t->vm->task_list;
while (t) {
if ( t->id && !strcmp(t->id, name) ) {
this_task:
t->flags |= SPL_TASK_FLAG_PUBLIC;
return SPL_NEW_INT(0);
}
t= t->next;
}
return SPL_NEW_INT(1);
}
/**
* Returns the name of the current task.
*/
// builtin task_getname()
static struct spl_node *handler_task_getname(struct spl_task *t, void *d UNUSED)
{
return t->id ? SPL_NEW_STRING_DUP(t->id) : spl_get(0);
}
/**
* Returns 1 if the specified task exists and 0 otherwise.
*/
// builtin task_check(name)
static struct spl_node *handler_task_check(struct spl_task *t, void *d UNUSED)
{
char *name = spl_clib_get_string(t);
if ( !name[0] ) goto this_task;
t = t->vm->task_list;
while (t) {
if ( t->id && !strcmp(t->id, name) ) {
this_task:
return SPL_NEW_INT(1);
}
t= t->next;
}
return SPL_NEW_INT(0);
}
/**
* Pauses current task for given amount of time,
* without consuming processing time.
* After the time has elapsed (or an external signal is received),
* the task is automatically resumed (in contrast to task_pause).
*
* The time can be given as a float value, representing seconds
* and fraction of seconds.
*
* TODO: sleep affects the process, not the task, find a task equivalent
*/
// builtin task_sleep(seconds)
static struct spl_node *handler_task_sleep(struct spl_task *t, void *d UNUSED)
{
float f = spl_clib_get_float(t);
if (f < 0)
return SPL_NEW_INT(0);
unsigned int seconds = (unsigned int)f;
#ifndef USEWIN32API
useconds_t useconds = f-seconds;
#endif
sleep(seconds);
#ifndef USEWIN32API
usleep(useconds);
#endif
return SPL_NEW_INT(0);
}
void SPL_ABI(spl_mod_task_init)(struct spl_vm *vm, struct spl_module *mod UNUSED, int restore UNUSED)
{
spl_clib_reg(vm, "task_create", handler_task_create, 0);
spl_clib_reg(vm, "__task_kill", handler_task_kill, 0);
spl_clib_reg(vm, "task_pause", handler_task_pause, 0);
spl_clib_reg(vm, "task_continue", handler_task_continue, 0);
spl_clib_reg(vm, "task_system", handler_task_system, 0);
spl_clib_reg(vm, "task_public", handler_task_public, 0);
spl_clib_reg(vm, "task_getname", handler_task_getname, 0);
spl_clib_reg(vm, "task_check", handler_task_check, 0);
spl_clib_reg(vm, "task_sleep", handler_task_sleep, 0);
if ( !restore )
spl_eval_bytecode(vm, 0, strdup(mod->name), &bytecode);
}
void SPL_ABI(spl_mod_task_done)(struct spl_vm *vm UNUSED, struct spl_module *mod UNUSED)
{
return;
}
|