Kernel.cpp

Go to the documentation of this file.
00001 /*
00002 Copyright (C) 2002-2006 The Pentagram team
00003 
00004 This program is free software; you can redistribute it and/or
00005 modify it under the terms of the GNU General Public License
00006 as published by the Free Software Foundation; either version 2
00007 of the License, or (at your option) any later version.
00008 
00009 This program is distributed in the hope that it will be useful,
00010 but WITHOUT ANY WARRANTY; without even the implied warranty of
00011 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012 GNU General Public License for more details.
00013 
00014 You should have received a copy of the GNU General Public License
00015 along with this program; if not, write to the Free Software
00016 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
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         // if we're in frame-by-frame mode, reset to a paused state
00074         if (framebyframe) paused = 1;
00075 }
00076 
00077 ProcId Kernel::assignPID(Process* proc)
00078 {
00079         // to prevent new processes from getting a PID while loading
00080         if (loading) return 0xFFFF;
00081 
00082         // Get a pID
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 //      processes.push_back(proc);
00105 //      proc->active = true;
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                         // Clear pid
00154                         pIDs->clearID(proc->pid);
00155 
00156                         return;
00157                 }
00158         }
00159 }
00160 
00161 
00162 //Q: is returning a 'dirty' flag really useful?
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                         // process is killed, so remove it from the list
00197                         current_process = processes.erase(current_process);
00198                                 
00199                         // Clear pid
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 & /*argv*/)
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                 // Don't count us, we are not really here
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                 // Don't count us, we are not really here
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 /*argsize*/)
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 /*argsize*/)
00482 {
00483         ARG_OBJID(item);
00484         ARG_UINT16(type);
00485 
00486         Kernel::get_instance()->killProcesses(item, type, true);
00487         return 0;
00488 }

Generated on Fri Jul 27 22:27:22 2007 for pentagram by  doxygen 1.4.7