00001
00002
00003
00004
00005
00006
00007
00008 #include "wvcont.h"
00009 #include "wvtask.h"
00010 #include "wvlinklist.h"
00011 #include <assert.h>
00012
00013
00014 struct WvCont::Data
00015 {
00016 int links;
00017 int mydepth;
00018 bool finishing;
00019
00020 size_t stacksize;
00021 WvTaskMan *taskman;
00022 WvTask *task;
00023
00024 WvContCallback cb;
00025 void *ret;
00026 void *p1;
00027
00028 Data(const WvContCallback &_cb, size_t _stacksize) : cb(_cb)
00029 { links = 1; finishing = false; stacksize = _stacksize; mydepth = 0;
00030 taskman = WvTaskMan::get();
00031 task = NULL; report();
00032 if (data_list == NULL)
00033 data_list = new DataList;
00034 data_list->append(this, false);
00035 }
00036 ~Data();
00037
00038 void link()
00039 { links++; report(); }
00040 void unlink()
00041 { links--; report(); if (!links) delete this; }
00042
00043 void report()
00044 { }
00045 };
00046
00047
00048 WvCont::Data *WvCont::curdata = NULL;
00049 int WvCont::taskdepth = 0;
00050
00051
00052 WvCont::DataList *WvCont::data_list = NULL;
00053
00054
00055 WvCont::WvCont(const WvCont &cb)
00056 {
00057 static bool first = true;
00058 if (first)
00059 {
00060 first = false;
00061 WvStreamsDebugger::add_command("conts", 0,
00062 debugger_conts_run_cb, 0);
00063 }
00064
00065 data = cb.data;
00066 data->link();
00067 }
00068
00069
00070 WvCont::WvCont(const WvContCallback &cb, unsigned long _stacksize)
00071 {
00072 data = new Data(cb, (size_t)_stacksize);
00073 }
00074
00075
00076 WvCont::WvCont(Data *data)
00077 {
00078 this->data = data;
00079 data->link();
00080 }
00081
00082
00083 WvCont::~WvCont()
00084 {
00085 if (data->links == 1)
00086 {
00087 data->finishing = true;
00088 data->p1 = NULL;
00089 while (data->task && data->task->isrunning())
00090 call();
00091 }
00092
00093 data->unlink();
00094 }
00095
00096
00097 WvCont::Data::~Data()
00098 {
00099 assert(!links);
00100
00101 if (task)
00102 task->recycle();
00103 taskman->unlink();
00104
00105 report();
00106
00107 data_list->unlink(this);
00108 if (data_list->isempty())
00109 {
00110 delete data_list;
00111 data_list = NULL;
00112 }
00113 }
00114
00115
00116 static inline const char *Yes_No(bool val)
00117 {
00118 return val? "Yes": "No";
00119 }
00120
00121
00122 WvString WvCont::debugger_conts_run_cb(WvStringParm cmd, WvStringList &args,
00123 WvStreamsDebugger::ResultCallback result_cb, void *)
00124 {
00125 const char *format = "%5s%s%5s%s%9s%s%10s%s%7s%s%s";
00126 WvStringList result;
00127 result.append(format, "Links", "-", "Depth", "-", "Finishing", "-", "Stack Size",
00128 "-", "Task ID", "-", "Task Name------");
00129 result_cb(cmd, result);
00130
00131 if (!data_list)
00132 return WvString::null;
00133
00134 DataList::Iter i(*data_list);
00135 for (i.rewind(); i.next(); )
00136 {
00137 result.zap();
00138 result.append(format,
00139 i->links, " ", i->mydepth, " ", Yes_No(i->finishing), " ",
00140 i->stacksize, " ",
00141 i->task? WvString(i->task->get_tid()): WvString("n/a"), " ",
00142 i->task? i->task->get_name(): WvString("n/a"));
00143 result_cb(cmd, result);
00144 }
00145
00146 return WvString::null;
00147 }
00148
00149
00150
00151 void *WvCont::_call(Data *data)
00152 {
00153 Data *olddata = curdata;
00154 curdata = data;
00155 data->link();
00156
00157
00158
00159
00160
00161
00162
00163
00164
00165
00166
00167
00168
00169 assert(!data->mydepth);
00170 data->mydepth = ++taskdepth;
00171 do
00172 {
00173 assert(data->task);
00174 do
00175 {
00176 data->taskman->run(*data->task);
00177 if (data->links == 1)
00178 {
00179 data->finishing = true;
00180 data->p1 = NULL;
00181 }
00182 } while (data->finishing && data->task && data->task->isrunning());
00183 assert(data->links);
00184 } while (taskdepth > data->mydepth);
00185 assert(taskdepth == data->mydepth);
00186 taskdepth--;
00187 data->mydepth = 0;
00188
00189 void *ret = data->ret;
00190 data->unlink();
00191 curdata = olddata;
00192 return ret;
00193 }
00194
00195
00196 void *WvCont::operator() (void *p1)
00197 {
00198 data->ret = reinterpret_cast<void*>(-42);
00199
00200 if (!data->task)
00201 data->task = data->taskman->start("wvcont", bouncer, data,
00202 data->stacksize);
00203 else if (!data->task->isrunning())
00204 data->task->start("wvcont+", bouncer, data);
00205
00206 assert(data->task);
00207
00208 data->p1 = p1;
00209 return call();
00210 }
00211
00212
00213 WvCont WvCont::current()
00214 {
00215 assert(curdata);
00216 assert(curdata->task == curdata->taskman->whoami());
00217 assert(isok());
00218 return WvCont(curdata);
00219 }
00220
00221
00222 void *WvCont::yield(void *ret)
00223 {
00224 assert(curdata);
00225 assert(curdata->task == curdata->taskman->whoami());
00226
00227
00228
00229
00230 assert(isok());
00231
00232 curdata->ret = ret;
00233 curdata->taskman->yield();
00234 return curdata->p1;
00235 }
00236
00237
00238 bool WvCont::isok()
00239 {
00240
00241 if (!curdata)
00242 return false;
00243
00244 assert(curdata->task == curdata->taskman->whoami());
00245 return !curdata->finishing;
00246 }
00247
00248
00249 void WvCont::bouncer(void *userdata)
00250 {
00251 Data *data = (Data *)userdata;
00252
00253
00254
00255
00256 data->ret = data->cb(data->p1);
00257 }