00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 #include "pent_include.h"
00020
00021 #include "Kernel.h"
00022 #include "Process.h"
00023 #include "idMan.h"
00024
00025 #include "IDataSource.h"
00026 #include "ODataSource.h"
00027
00028 #include <map>
00029
00030 typedef std::list<Process *>::iterator ProcessIterator;
00031
00032 Kernel* Kernel::kernel = 0;
00033
00034 Kernel::Kernel() : loading(false)
00035 {
00036 con.Print(MM_INFO, "Creating Kernel...\n");
00037
00038 assert(kernel == 0);
00039 kernel = this;
00040 pIDs = new idMan(1,32766,128);
00041 current_process = processes.end();
00042 framenum = 0;
00043 paused = 0;
00044 runningprocess = 0;
00045 framebyframe = false;
00046 }
00047
00048 Kernel::~Kernel()
00049 {
00050 reset();
00051 con.Print(MM_INFO, "Destroying Kernel...\n");
00052
00053 kernel = 0;
00054
00055 delete pIDs;
00056 }
00057
00058 void Kernel::reset()
00059 {
00060 con.Print(MM_INFO, "Resetting Kernel...\n");
00061
00062 for (ProcessIterator it = processes.begin(); it != processes.end(); ++it) {
00063 delete (*it);
00064 }
00065 processes.clear();
00066 current_process = processes.begin();
00067
00068 pIDs->clearAll();
00069
00070 paused = 0;
00071 runningprocess = 0;
00072
00073
00074 if (framebyframe) paused = 1;
00075 }
00076
00077 ProcId Kernel::assignPID(Process* proc)
00078 {
00079
00080 if (loading) return 0xFFFF;
00081
00082
00083 proc->pid = pIDs->getNewID();
00084
00085 return proc->pid;
00086 }
00087
00088 ProcId Kernel::addProcess(Process* proc)
00089 {
00090 #if 0
00091 for (ProcessIterator it = processes.begin(); it != processes.end(); ++it) {
00092 if (*it == proc)
00093 return 0;
00094 }
00095 #endif
00096
00097 assert(proc->pid != 0 && proc->pid != 0xFFFF);
00098
00099 #if 0
00100 perr << "[Kernel] Adding process " << proc
00101 << ", pid = " << proc->pid << std::endl;
00102 #endif
00103
00104
00105
00106 setNextProcess(proc);
00107 return proc->pid;
00108 }
00109
00110 ProcId Kernel::addProcessExec(Process* proc)
00111 {
00112 #if 0
00113 for (ProcessIterator it = processes.begin(); it != processes.end(); ++it) {
00114 if (*it == proc)
00115 return 0;
00116 }
00117 #endif
00118
00119 assert(proc->pid != 0 && proc->pid != 0xFFFF);
00120
00121 #if 0
00122 perr << "[Kernel] Adding process " << proc
00123 << ", pid = " << proc->pid << std::endl;
00124 #endif
00125
00126 processes.push_back(proc);
00127 proc->flags |= Process::PROC_ACTIVE;
00128
00129 Process* oldrunning = runningprocess; runningprocess = proc;
00130 proc->run(framenum);
00131 runningprocess = oldrunning;
00132
00133 return proc->pid;
00134 }
00135
00136 void Kernel::removeProcess(Process* proc)
00137 {
00144
00145 for (ProcessIterator it = processes.begin(); it != processes.end(); ++it) {
00146 if (*it == proc) {
00147 proc->flags &= ~Process::PROC_ACTIVE;
00148
00149 perr << "[Kernel] Removing process " << proc << std::endl;
00150
00151 processes.erase(it);
00152
00153
00154 pIDs->clearID(proc->pid);
00155
00156 return;
00157 }
00158 }
00159 }
00160
00161
00162
00163 bool Kernel::runProcesses()
00164 {
00165 if (!paused)
00166 framenum++;
00167
00168 if (processes.size() == 0) {
00169 return true;
00170 perr << "Process queue is empty?! Aborting.\n";
00171
00173 exit(0);
00174 }
00175 bool dirty = false;
00176 current_process = processes.begin();
00177 while (current_process != processes.end()) {
00178 Process* p = *current_process;
00179
00180 if (!paused && ((p->flags & (Process::PROC_TERMINATED |
00181 Process::PROC_TERM_DEFERRED))
00182 == Process::PROC_TERM_DEFERRED))
00183 {
00184 p->terminate();
00185 }
00186 if (!(p->is_terminated() || p->is_suspended()) &&
00187 (!paused || (p->flags & Process::PROC_RUNPAUSED)))
00188 {
00189 runningprocess = p;
00190 bool ret = p->run(framenum);
00191 runningprocess = 0;
00192
00193 if (ret) dirty = true;
00194 }
00195 if (!paused && (p->flags & Process::PROC_TERMINATED)) {
00196
00197 current_process = processes.erase(current_process);
00198
00199
00200 pIDs->clearID(p->pid);
00201
00203 delete p;
00204 }
00205 else
00206 ++current_process;
00207 }
00208
00209 if (!paused && framebyframe) pause();
00210
00211 return dirty;
00212 }
00213
00214 void Kernel::setNextProcess(Process* proc)
00215 {
00216 if (current_process != processes.end() && *current_process == proc) return;
00217
00218 if (proc->flags & Process::PROC_ACTIVE) {
00219 for (ProcessIterator it = processes.begin();
00220 it != processes.end(); ++it) {
00221 if (*it == proc) {
00222 processes.erase(it);
00223 break;
00224 }
00225 }
00226 } else {
00227 proc->flags |= Process::PROC_ACTIVE;
00228 }
00229
00230 if (current_process == processes.end()) {
00231 processes.push_front(proc);
00232 } else {
00233 ProcessIterator t = current_process;
00234 ++t;
00235
00236 processes.insert(t, proc);
00237 }
00238 }
00239
00240 Process* Kernel::getProcess(ProcId pid)
00241 {
00242 for (ProcessIterator it = processes.begin(); it != processes.end(); ++it) {
00243 Process* p = *it;
00244 if (p->pid == pid)
00245 return p;
00246 }
00247 return 0;
00248 }
00249
00250 void Kernel::kernelStats()
00251 {
00252 pout << "Kernel memory stats:" << std::endl;
00253 pout << "Processes : " << processes.size() << "/32765" << std::endl;
00254 }
00255
00256 void Kernel::processTypes()
00257 {
00258 pout << "Current process types:" << std::endl;
00259 std::map<std::string, unsigned int> processtypes;
00260 for (ProcessIterator it = processes.begin(); it != processes.end(); ++it) {
00261 Process* p = *it;
00262 processtypes[p->GetClassType().class_name]++;
00263 }
00264 std::map<std::string, unsigned int>::iterator iter;
00265 for (iter = processtypes.begin(); iter != processtypes.end(); ++iter) {
00266 pout << (*iter).first << ": " << (*iter).second << std::endl;
00267 }
00268 }
00269
00270 void Kernel::ConCmd_processTypes(const Console::ArgvType & )
00271 {
00272 Kernel::get_instance()->processTypes();
00273 }
00274
00275 void Kernel::ConCmd_listProcesses(const Console::ArgvType &argv)
00276 {
00277 if (argv.size() > 2) {
00278 pout << "usage: listProcesses [<itemnum>]" << std::endl;
00279 return;
00280 }
00281
00282 Kernel* kernel = Kernel::get_instance();
00283 ObjId item = 0;
00284 if (argv.size() == 2) {
00285 item = strtol(argv[1].c_str(), 0, 0);
00286 pout << "Processes for item " << item << ":" << std::endl;
00287 } else {
00288 pout << "Processes:" << std::endl;
00289 }
00290 for (ProcessIterator it = kernel->processes.begin();
00291 it != kernel->processes.end(); ++it)
00292 {
00293 Process* p = *it;
00294 if (argv.size() == 1 || p->item_num == item)
00295 p->dumpInfo();
00296 }
00297
00298 }
00299
00300 void Kernel::ConCmd_processInfo(const Console::ArgvType& argv)
00301 {
00302 if (argv.size() != 2) {
00303 pout << "usage: processInfo <objectnum>" << std::endl;
00304 return;
00305 }
00306
00307 Kernel* kernel = Kernel::get_instance();
00308
00309 ProcId procid = strtol(argv[1].c_str(), 0, 0);
00310
00311 Process* p = kernel->getProcess(procid);
00312 if (p == 0) {
00313 pout << "No such process: " << procid << std::endl;
00314 } else {
00315 p->dumpInfo();
00316 }
00317 }
00318
00319 void Kernel::ConCmd_toggleFrameByFrame(const Console::ArgvType& argv)
00320 {
00321 Kernel* kernel = Kernel::get_instance();
00322 bool fbf = !kernel->isFrameByFrame();
00323 kernel->setFrameByFrame(fbf);
00324 pout << "FrameByFrame = " << fbf << std::endl;
00325 if (fbf)
00326 kernel->pause();
00327 else
00328 kernel->unpause();
00329 }
00330
00331 void Kernel::ConCmd_advanceFrame(const Console::ArgvType& argv)
00332 {
00333 Kernel* kernel = Kernel::get_instance();
00334 if (kernel->isFrameByFrame()) {
00335 kernel->unpause();
00336 pout << "FrameByFrame: Next Frame" << std::endl;
00337 }
00338 }
00339
00340 uint32 Kernel::getNumProcesses(ObjId objid, uint16 processtype)
00341 {
00342 uint32 count = 0;
00343
00344 for (ProcessIterator it = processes.begin(); it != processes.end(); ++it)
00345 {
00346 Process* p = *it;
00347
00348
00349 if (p->is_terminated()) continue;
00350
00351 if ((objid == 0 || objid == p->item_num) &&
00352 (processtype == 6 || processtype == p->type))
00353 count++;
00354 }
00355
00356 return count;
00357 }
00358
00359 Process* Kernel::findProcess(ObjId objid, uint16 processtype)
00360 {
00361 for (ProcessIterator it = processes.begin(); it != processes.end(); ++it)
00362 {
00363 Process* p = *it;
00364
00365
00366 if (p->is_terminated()) continue;
00367
00368 if ((objid == 0 || objid == p->item_num) &&
00369 (processtype == 6 || processtype == p->type))
00370 {
00371 return p;
00372 }
00373 }
00374
00375 return 0;
00376 }
00377
00378
00379 void Kernel::killProcesses(ObjId objid, uint16 processtype, bool fail)
00380 {
00381 for (ProcessIterator it = processes.begin(); it != processes.end(); ++it)
00382 {
00383 Process* p = *it;
00384
00385 if (p->item_num != 0 && (objid == 0 || objid == p->item_num) &&
00386 (processtype == 6 || processtype == p->type) &&
00387 !(p->flags & Process::PROC_TERMINATED) &&
00388 !(p->flags & Process::PROC_TERM_DEFERRED))
00389 {
00390 if (fail)
00391 p->fail();
00392 else
00393 p->terminate();
00394 }
00395 }
00396 }
00397
00398 void Kernel::killProcessesNotOfType(ObjId objid, uint16 processtype, bool fail)
00399 {
00400 for (ProcessIterator it = processes.begin(); it != processes.end(); ++it)
00401 {
00402 Process* p = *it;
00403
00404 if (p->item_num != 0 && (objid == 0 || objid == p->item_num) &&
00405 (p->type != processtype) &&
00406 !(p->flags & Process::PROC_TERMINATED) &&
00407 !(p->flags & Process::PROC_TERM_DEFERRED))
00408 {
00409 if (fail)
00410 p->fail();
00411 else
00412 p->terminate();
00413 }
00414 }
00415 }
00416
00417 void Kernel::save(ODataSource* ods)
00418 {
00419 ods->write4(framenum);
00420 pIDs->save(ods);
00421 ods->write4(processes.size());
00422 for (ProcessIterator it = processes.begin(); it != processes.end(); ++it)
00423 {
00424 (*it)->save(ods);
00425 }
00426 }
00427
00428 bool Kernel::load(IDataSource* ids, uint32 version)
00429 {
00430 framenum = ids->read4();
00431
00432 if (!pIDs->load(ids, version)) return false;
00433
00434 uint32 pcount = ids->read4();
00435
00436 for (unsigned int i = 0; i < pcount; ++i) {
00437 Process* p = loadProcess(ids, version);
00438 if (!p) return false;
00439 processes.push_back(p);
00440 }
00441
00442 return true;
00443 }
00444
00445 Process* Kernel::loadProcess(IDataSource* ids, uint32 version)
00446 {
00447 uint16 classlen = ids->read2();
00448 char* buf = new char[classlen+1];
00449 ids->read(buf, classlen);
00450 buf[classlen] = 0;
00451
00452 std::string classname = buf;
00453 delete[] buf;
00454
00455 std::map<std::string, ProcessLoadFunc>::iterator iter;
00456 iter = processloaders.find(classname);
00457
00458 if (iter == processloaders.end()) {
00459 perr << "Unknown Process class: " << classname << std::endl;
00460 return 0;
00461 }
00462
00463
00464 loading = true;
00465
00466 Process* p = (*(iter->second))(ids, version);
00467
00468 loading = false;
00469
00470 return p;
00471 }
00472
00473 uint32 Kernel::I_getNumProcesses(const uint8* args, unsigned int )
00474 {
00475 ARG_OBJID(item);
00476 ARG_UINT16(type);
00477
00478 return Kernel::get_instance()->getNumProcesses(item, type);
00479 }
00480
00481 uint32 Kernel::I_resetRef(const uint8* args, unsigned int )
00482 {
00483 ARG_OBJID(item);
00484 ARG_UINT16(type);
00485
00486 Kernel::get_instance()->killProcesses(item, type, true);
00487 return 0;
00488 }