00001
00002
00003
00004
00005
00006
00007
00008
#include "wvcont.h"
00009
#include "wvtask.h"
00010
00011
00012
struct WvCont::Data
00013 {
00014
int links;
00015
int mydepth;
00016
bool finishing;
00017
00018 size_t stacksize;
00019
WvTaskMan *taskman;
00020
WvTask *task;
00021
00022 Callback cb;
00023 R ret;
00024 P1 p1;
00025
00026 Data(
const Callback &_cb, size_t _stacksize) : cb(_cb)
00027 { links = 1; finishing =
false; stacksize = _stacksize; mydepth = 0;
00028 taskman =
WvTaskMan::get();
00029 task = NULL; report(); }
00030 ~Data()
00031 { assert(!links); taskman->unlink(); report(); }
00032
00033
void link()
00034 { links++; report(); }
00035
void unlink()
00036 { links--; report();
if (!links)
delete this; }
00037
00038
void report()
00039 { }
00040 };
00041
00042
00043 WvCont::Data *WvCont::curdata = NULL;
00044
int WvCont::taskdepth = 0;
00045
00046
00047 WvCont::WvCont(
const WvCont &cb)
00048 {
00049 data = cb.
data;
00050 data->link();
00051 }
00052
00053
00054 WvCont::WvCont(
const Callback &cb,
unsigned long _stacksize)
00055 {
00056 data =
new Data(cb, (size_t)_stacksize);
00057 }
00058
00059
00060 WvCont::~WvCont()
00061 {
00062
if (data->links == 1)
00063 {
00064
00065 data->finishing =
true;
00066
while (data->task && data->task->isrunning())
00067 call();
00068
00069
if (data->task)
00070 data->task->recycle();
00071 }
00072 data->unlink();
00073 }
00074
00075
00076
00077
void WvCont::call()
00078 {
00079 Data *olddata = curdata;
00080 curdata = data;
00081
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094 assert(!data->mydepth);
00095 data->mydepth = ++taskdepth;
00096
do
00097 {
00098 data->taskman->run(*data->task);
00099 }
while (taskdepth > data->mydepth);
00100 assert(taskdepth == data->mydepth);
00101 taskdepth--;
00102 data->mydepth = 0;
00103
00104 curdata = olddata;
00105 }
00106
00107
00108 WvCont::WvCont(Data *data)
00109 {
00110 this->data = data;
00111 data->link();
00112 }
00113
00114
00115 WvCont::R WvCont::operator() (
P1 p1)
00116 {
00117 data->ret =
R(-42);
00118
00119
if (!data->task)
00120 data->task = data->taskman->start(
"wvcont", bouncer, data,
00121 data->stacksize);
00122
else if (!data->task->isrunning())
00123 data->task->start(
"wvcont+", bouncer, data);
00124
00125 data->p1 = p1;
00126 call();
00127
return data->ret;
00128 }
00129
00130
00131 WvCont WvCont::current()
00132 {
00133 assert(curdata);
00134 assert(curdata->task == curdata->taskman->whoami());
00135 assert(
isok());
00136
return WvCont(curdata);
00137 }
00138
00139
00140 WvCont::P1 WvCont::yield(R ret)
00141 {
00142 assert(curdata);
00143 assert(curdata->task == curdata->taskman->whoami());
00144 assert(
isok());
00145 curdata->ret = ret;
00146 curdata->taskman->yield();
00147
return curdata->p1;
00148 }
00149
00150
00151 bool WvCont::isok()
00152 {
00153 assert(curdata);
00154 assert(curdata->task == curdata->taskman->whoami());
00155
return !curdata->finishing;
00156 }
00157
00158
00159
void WvCont::bouncer(
void *userdata)
00160 {
00161 Data *data = (Data *)userdata;
00162
00163
00164
00165
00166 data->ret = data->cb(data->p1);
00167 }
00168
00169