00001
00002
00003
00004
00005
00006
00007
00008 #include "wvcont.h"
00009 #include "wvtask.h"
00010 #include <assert.h>
00011
00012
00013 struct WvCont::Data
00014 {
00015 int links;
00016 int mydepth;
00017 bool finishing;
00018
00019 size_t stacksize;
00020 WvTaskMan *taskman;
00021 WvTask *task;
00022
00023 WvContCallback cb;
00024 void *ret;
00025 void *p1;
00026
00027 Data(const WvContCallback &_cb, size_t _stacksize) : cb(_cb)
00028 { links = 1; finishing = false; stacksize = _stacksize; mydepth = 0;
00029 taskman = WvTaskMan::get();
00030 task = NULL; report(); }
00031 ~Data();
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 WvContCallback &cb, unsigned long _stacksize)
00055 {
00056 data = new Data(cb, (size_t)_stacksize);
00057 }
00058
00059
00060 WvCont::WvCont(Data *data)
00061 {
00062 this->data = data;
00063 data->link();
00064 }
00065
00066
00067 WvCont::~WvCont()
00068 {
00069 if (data->links == 1)
00070 {
00071 data->finishing = true;
00072 data->p1 = NULL;
00073 while (data->task && data->task->isrunning())
00074 call();
00075 }
00076
00077 data->unlink();
00078 }
00079
00080
00081 WvCont::Data::~Data()
00082 {
00083 assert(!links);
00084
00085 if (task)
00086 task->recycle();
00087 taskman->unlink();
00088
00089 report();
00090 }
00091
00092
00093
00094 void *WvCont::_call(Data *data)
00095 {
00096 Data *olddata = curdata;
00097 curdata = data;
00098 data->link();
00099
00100
00101
00102
00103
00104
00105
00106
00107
00108
00109
00110
00111
00112 assert(!data->mydepth);
00113 data->mydepth = ++taskdepth;
00114 do
00115 {
00116 assert(data->task);
00117 do
00118 {
00119 data->taskman->run(*data->task);
00120 if (data->links == 1)
00121 {
00122 data->finishing = true;
00123 data->p1 = NULL;
00124 }
00125 } while (data->finishing && data->task && data->task->isrunning());
00126 assert(data->links);
00127 } while (taskdepth > data->mydepth);
00128 assert(taskdepth == data->mydepth);
00129 taskdepth--;
00130 data->mydepth = 0;
00131
00132 void *ret = data->ret;
00133 data->unlink();
00134 curdata = olddata;
00135 return ret;
00136 }
00137
00138
00139 void *WvCont::operator() (void *p1)
00140 {
00141 data->ret = reinterpret_cast<void*>(-42);
00142
00143 if (!data->task)
00144 data->task = data->taskman->start("wvcont", bouncer, data,
00145 data->stacksize);
00146 else if (!data->task->isrunning())
00147 data->task->start("wvcont+", bouncer, data);
00148
00149 assert(data->task);
00150
00151 data->p1 = p1;
00152 return call();
00153 }
00154
00155
00156 WvCont WvCont::current()
00157 {
00158 assert(curdata);
00159 assert(curdata->task == curdata->taskman->whoami());
00160 assert(isok());
00161 return WvCont(curdata);
00162 }
00163
00164
00165 void *WvCont::yield(void *ret)
00166 {
00167 assert(curdata);
00168 assert(curdata->task == curdata->taskman->whoami());
00169
00170
00171
00172
00173 assert(isok());
00174
00175 curdata->ret = ret;
00176 curdata->taskman->yield();
00177 return curdata->p1;
00178 }
00179
00180
00181 bool WvCont::isok()
00182 {
00183
00184 if (!curdata)
00185 return false;
00186
00187 assert(curdata->task == curdata->taskman->whoami());
00188 return !curdata->finishing;
00189 }
00190
00191
00192 void WvCont::bouncer(void *userdata)
00193 {
00194 Data *data = (Data *)userdata;
00195
00196
00197
00198
00199 data->ret = data->cb(data->p1);
00200 }