00001
00002
00003
00004
00005
00006 #define WIN32_LEAN_AND_MEAN
00007 #define NOMINMAX
00008 #ifndef _WIN32_WINNT
00009 #define _WIN32_WINNT 0x0400
00010 #endif
00011 #include <windows.h>
00012 #include <winbase.h>
00013
00014 #include "wvwin32task.h"
00015 #include <stdio.h>
00016 #include <stdlib.h>
00017 #include <assert.h>
00018 #include <malloc.h>
00019 #include <stdlib.h>
00020
00021 int WvTask::taskcount, WvTask::numtasks, WvTask::numrunning;
00022
00023 WvTaskMan *WvTaskMan::singleton = NULL;
00024 int WvTaskMan::links = 1;
00025
00026 int WvTaskMan::magic_number;
00027 WvTaskList WvTaskMan::free_tasks;
00028
00029 WvTask *WvTaskMan::stack_target;
00030
00031 WvTask *WvTaskMan::current_task;
00032 LPVOID WvTaskMan::toplevel;
00033
00034 WvTask::WvTask(WvTaskMan &_man, size_t _stacksize) : man(_man)
00035 {
00036 stacksize = _stacksize;
00037 running = recycled = false;
00038 func = NULL;
00039 userdata = NULL;
00040
00041 tid = ++taskcount;
00042 numtasks++;
00043 magic_number = WVTASK_MAGIC;
00044 stack_magic = NULL;
00045
00046 mystate = CreateFiber(_stacksize, &MyFiberProc, this);
00047 assert(mystate);
00048 }
00049
00050
00051 WvTask::~WvTask()
00052 {
00053 numtasks--;
00054 if (running)
00055 numrunning--;
00056 magic_number = 42;
00057 }
00058
00059 VOID CALLBACK WvTask::MyFiberProc(PVOID lpParameter)
00060 {
00061 WvTask *_this = (WvTask *) lpParameter;
00062 while (true)
00063 {
00064 if (_this->func && _this->running)
00065 {
00066 _this->func(_this->userdata);
00067
00068
00069 _this->name = "DEAD";
00070 _this->running = false;
00071 _this->numrunning--;
00072 }
00073 _this->man.yield();
00074 }
00075 }
00076
00077 void WvTask::start(WvStringParm _name, TaskFunc *_func, void *_userdata)
00078 {
00079 assert(!recycled);
00080 name = _name;
00081 func = _func;
00082 userdata = _userdata;
00083 running = true;
00084 numrunning++;
00085 }
00086
00087
00088 void WvTask::recycle()
00089 {
00090 assert(!running);
00091
00092 if (!running && !recycled)
00093 {
00094 man.free_tasks.append(this, true);
00095 recycled = true;
00096 }
00097 }
00098
00099 WvTaskMan *WvTaskMan::get()
00100 {
00101 if (!singleton)
00102 singleton = new WvTaskMan;
00103 links++;
00104 return singleton;
00105 }
00106
00107
00108 void WvTaskMan::unlink()
00109 {
00110 links--;
00111 if (links == 0)
00112 {
00113 delete singleton;
00114 singleton = NULL;
00115 }
00116 }
00117
00118 WvTaskMan::WvTaskMan()
00119 {
00120 stack_target = NULL;
00121 current_task = NULL;
00122 magic_number = -WVTASK_MAGIC;
00123
00124 toplevel = ::ConvertThreadToFiber(0);
00125 assert(toplevel);
00126 }
00127
00128
00129 WvTaskMan::~WvTaskMan()
00130 {
00131 magic_number = -42;
00132 }
00133
00134
00135 WvTask *WvTaskMan::start(WvStringParm name,
00136 WvTask::TaskFunc *func, void *userdata,
00137 size_t stacksize)
00138 {
00139 WvTask *t;
00140
00141 WvTaskList::Iter i(free_tasks);
00142 for (i.rewind(); i.next(); )
00143 {
00144 if (i().stacksize >= stacksize)
00145 {
00146 t = &i();
00147 i.link->set_autofree(false);
00148 i.unlink();
00149 t->recycled = false;
00150 t->start(name, func, userdata);
00151 return t;
00152 }
00153 }
00154
00155 t = new WvTask(*this, stacksize);
00156 t->start(name, func, userdata);
00157 return t;
00158 }
00159
00160
00161 int WvTaskMan::run(WvTask &task, int val)
00162 {
00163 assert(magic_number == -WVTASK_MAGIC);
00164 assert(task.magic_number == WVTASK_MAGIC);
00165 assert(!task.recycled);
00166
00167 if (&task == current_task)
00168 return val;
00169
00170 WvTask *old_task = current_task;
00171 current_task = &task;
00172 LPVOID *state;
00173
00174 if (!old_task)
00175 state = &toplevel;
00176 else
00177 state = &old_task->mystate;
00178
00179
00180 ::SwitchToFiber(task.mystate);
00181
00182
00183
00184 current_task = old_task;
00185 int newval = 0;
00186 return newval;
00187 }
00188
00189
00190 int WvTaskMan::yield(int val)
00191 {
00192 if (!current_task)
00193 return 0;
00194
00195 WvTask *task = current_task;
00196
00197 current_task = 0;
00198 ::SwitchToFiber(toplevel);
00199
00200 assert(current_task == task);
00201
00202 int newval = 0;
00203 return newval;
00204 }