WvStreams
wvwin32task.cc
1/*
2 * Worldvisions Weaver Software:
3 * Copyright (C) 1997-2002 Net Integration Technologies, Inc.
4 *
5 */
6#define WIN32_LEAN_AND_MEAN
7//#define NOMINMAX
8#ifndef _WIN32_WINNT
9#define _WIN32_WINNT 0x0400
10#endif
11#include <windows.h>
12#include <winbase.h>
13
14#include "wvwin32task.h"
15#include <stdio.h>
16#include <stdlib.h>
17#include <assert.h>
18#include <malloc.h> // for alloca()
19#include <stdlib.h> // for alloca() on non-Linux platforms?
20
21int WvTask::taskcount, WvTask::numtasks, WvTask::numrunning;
22
23WvTaskMan *WvTaskMan::singleton = NULL;
24int WvTaskMan::links = 1; // never delete singleton
25
26int WvTaskMan::magic_number;
27WvTaskList WvTaskMan::free_tasks;
28
29WvTask *WvTaskMan::stack_target;
30
31WvTask *WvTaskMan::current_task;
32LPVOID WvTaskMan::toplevel;
33
34WvTask::WvTask(WvTaskMan &_man, size_t _stacksize) : man(_man)
35{
36 stacksize = _stacksize;
37 running = recycled = false;
38 func = NULL;
39 userdata = NULL;
40
41 tid = ++taskcount;
42 numtasks++;
43 magic_number = WVTASK_MAGIC;
44 stack_magic = NULL;
45
46 mystate = CreateFiber(_stacksize, &MyFiberProc, this);
47 assert(mystate);
48}
49
50
51WvTask::~WvTask()
52{
53 numtasks--;
54 if (running)
55 numrunning--;
56 magic_number = 42;
57}
58
59VOID CALLBACK WvTask::MyFiberProc(PVOID lpParameter)
60{
61 WvTask *_this = (WvTask *) lpParameter;
62 while (true)
63 {
64 if (_this->func && _this->running)
65 {
66 _this->func(_this->userdata);
67
68 // the task's function terminated.
69 _this->name = "DEAD";
70 _this->running = false;
71 _this->numrunning--;
72 }
73 _this->man.yield();
74 }
75}
76
77void WvTask::start(WvStringParm _name, TaskFunc *_func, void *_userdata)
78{
79 assert(!recycled);
80 name = _name;
81 func = _func;
82 userdata = _userdata;
83 running = true;
84 numrunning++;
85}
86
87
88void WvTask::recycle()
89{
90 assert(!running);
91
92 if (!running && !recycled)
93 {
94 man.free_tasks.append(this, true);
95 recycled = true;
96 }
97}
98
100{
101 if (!singleton)
102 singleton = new WvTaskMan;
103 links++;
104 return singleton;
105}
106
107
108void WvTaskMan::unlink()
109{
110 links--;
111 if (links == 0)
112 {
113 delete singleton;
114 singleton = NULL;
115 }
116}
117
118WvTaskMan::WvTaskMan()
119{
120 stack_target = NULL;
121 current_task = NULL;
122 magic_number = -WVTASK_MAGIC;
123
124 toplevel = ::ConvertThreadToFiber(0);
125 assert(toplevel);
126}
127
128
129WvTaskMan::~WvTaskMan()
130{
131 magic_number = -42;
132}
133
134
135WvTask *WvTaskMan::start(WvStringParm name,
136 WvTask::TaskFunc *func, void *userdata,
137 size_t stacksize)
138{
139 WvTask *t;
140
141 WvTaskList::Iter i(free_tasks);
142 for (i.rewind(); i.next(); )
143 {
144 if (i().stacksize >= stacksize)
145 {
146 t = &i();
147 i.link->set_autofree(false);
148 i.unlink();
149 t->recycled = false;
150 t->start(name, func, userdata);
151 return t;
152 }
153 }
154 // if we get here, no matching task was found.
155 t = new WvTask(*this, stacksize);
156 t->start(name, func, userdata);
157 return t;
158}
159
160
161int WvTaskMan::run(WvTask &task, int val)
162{
163 assert(magic_number == -WVTASK_MAGIC);
164 assert(task.magic_number == WVTASK_MAGIC);
165 assert(!task.recycled);
166
167 if (&task == current_task)
168 return val; // that's easy!
169
170 WvTask *old_task = current_task;
171 current_task = &task;
172 LPVOID *state;
173
174 if (!old_task)
175 state = &toplevel; // top-level call (not in an actual task yet)
176 else
177 state = &old_task->mystate;
178
179 //fprintf(stderr, "taskman: switching from %p to %p\n", old_task, &task);
180 ::SwitchToFiber(task.mystate);
181 //fprintf(stderr, "taskman: back in %p\n", old_task);
182
183 // someone did yield() (if toplevel) or run() on our task; exit
184 current_task = old_task;
185 int newval = 0;
186 return newval;
187}
188
189
190int WvTaskMan::yield(int val)
191{
192 if (!current_task)
193 return 0; // weird...
194
195 WvTask *task = current_task;
196 //fprintf(stderr, "taskman: yielding from %p to toplevel\n", task);
197 current_task = 0; // toplevel
198 ::SwitchToFiber(toplevel);
199 //fprintf(stderr, "taskman: return from yield in %p (%p)\n", current_task, task);
200 assert(current_task == task);
201
202 int newval = 0;
203 return newval;
204}
A WvFastString acts exactly like a WvString, but can take (const char *) strings without needing to a...
Definition: wvstring.h:94
Provides co-operative multitasking support among WvTask instances.
Definition: wvtask.h:81
static WvTaskMan * get()
get/dereference the singleton global WvTaskMan
Definition: wvtask.cc:138
Represents a single thread of control.
Definition: wvtask.h:35