178 lines
4.7 KiB
C++
178 lines
4.7 KiB
C++
/* ScummVM - Graphic Adventure Engine
|
|
*
|
|
* ScummVM is the legal property of its developers, whose names
|
|
* are too numerous to list here. Please refer to the COPYRIGHT
|
|
* file distributed with this source distribution.
|
|
*
|
|
* This program is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*
|
|
*/
|
|
|
|
#include "ultima/ultima8/kernel/process.h"
|
|
#include "ultima/ultima8/kernel/kernel.h"
|
|
#include "ultima/ultima8/ultima8.h"
|
|
|
|
namespace Ultima {
|
|
namespace Ultima8 {
|
|
|
|
DEFINE_RUNTIME_CLASSTYPE_CODE(Process)
|
|
|
|
Process::Process(ObjId it, uint16 ty)
|
|
: _pid(0xFFFF), _flags(0), _itemNum(it), _type(ty), _result(0), _ticksPerRun(2) {
|
|
Kernel::get_instance()->assignPID(this);
|
|
if (GAME_IS_CRUSADER) {
|
|
// Default kernel ticks per run of processes in Crusader
|
|
_ticksPerRun = 1;
|
|
}
|
|
}
|
|
|
|
void Process::fail() {
|
|
_flags |= PROC_FAILED;
|
|
terminate();
|
|
}
|
|
|
|
void Process::terminate() {
|
|
if (_flags & PROC_TERMINATED)
|
|
return;
|
|
|
|
Kernel *kernel = Kernel::get_instance();
|
|
|
|
// wake up waiting processes
|
|
for (const auto &pid : _waiting) {
|
|
Process *p = kernel->getProcess(pid);
|
|
if (p)
|
|
p->wakeUp(_result);
|
|
}
|
|
_waiting.clear();
|
|
|
|
_flags |= PROC_TERMINATED;
|
|
}
|
|
|
|
void Process::wakeUp(uint32 result) {
|
|
_result = result;
|
|
|
|
_flags &= ~PROC_SUSPENDED;
|
|
|
|
Kernel::get_instance()->setNextProcess(this);
|
|
|
|
onWakeUp();
|
|
}
|
|
|
|
void Process::waitFor(ProcId pid) {
|
|
assert(pid != _pid);
|
|
if (pid) {
|
|
Kernel *kernel = Kernel::get_instance();
|
|
|
|
// add this process to waiting list of other process
|
|
Process *p = kernel->getProcess(pid);
|
|
assert(p);
|
|
if (p->getProcessFlags() & PROC_TERMINATED) {
|
|
//warning("Proc %d wait for proc %d which is already terminated", _pid, pid);
|
|
return;
|
|
}
|
|
p->_waiting.push_back(_pid);
|
|
|
|
// Note: The original games sync itemnum between processes
|
|
// here if either one is zero, but that seems to break things
|
|
// for us so we don't do it.
|
|
}
|
|
|
|
_flags |= PROC_SUSPENDED;
|
|
}
|
|
|
|
void Process::waitFor(Process *proc) {
|
|
assert(this != proc);
|
|
ProcId pid = 0;
|
|
if (proc) pid = proc->getPid();
|
|
|
|
waitFor(pid);
|
|
}
|
|
|
|
void Process::suspend() {
|
|
_flags |= PROC_SUSPENDED;
|
|
}
|
|
|
|
Common::String Process::dumpInfo() const {
|
|
Common::String info = Common::String::format(
|
|
"Process %d class %s, item %d, type %x, status ",
|
|
getPid(), GetClassType()._className, _itemNum, _type);
|
|
|
|
if (_flags & PROC_ACTIVE) info += "A";
|
|
if (_flags & PROC_SUSPENDED) info += "S";
|
|
if (_flags & PROC_TERMINATED) info += "T";
|
|
if (_flags & PROC_TERM_DEFERRED) info += "t";
|
|
if (_flags & PROC_FAILED) info += "F";
|
|
if (_flags & PROC_RUNPAUSED) info += "R";
|
|
if (_flags & PROC_TERM_DISPOSE) info += "D";
|
|
|
|
if (!_waiting.empty()) {
|
|
info += ", notify: ";
|
|
for (Std::vector<ProcId>::const_iterator i = _waiting.begin(); i != _waiting.end(); ++i) {
|
|
if (i != _waiting.begin()) info += ", ";
|
|
info += Common::String::format("%d", *i);
|
|
}
|
|
}
|
|
|
|
return info;
|
|
}
|
|
|
|
void Process::saveData(Common::WriteStream *ws) {
|
|
ws->writeUint16LE(_pid);
|
|
ws->writeUint32LE(_flags);
|
|
ws->writeUint16LE(_itemNum);
|
|
ws->writeUint16LE(_type);
|
|
ws->writeUint32LE(_result);
|
|
ws->writeUint32LE(static_cast<uint32>(_waiting.size()));
|
|
for (unsigned int i = 0; i < _waiting.size(); ++i)
|
|
ws->writeUint16LE(_waiting[i]);
|
|
}
|
|
|
|
bool Process::loadData(Common::ReadStream *rs, uint32 version) {
|
|
_pid = rs->readUint16LE();
|
|
_flags = rs->readUint32LE();
|
|
_itemNum = rs->readUint16LE();
|
|
_type = rs->readUint16LE();
|
|
_result = rs->readUint32LE();
|
|
uint32 waitcount = rs->readUint32LE();
|
|
|
|
if (waitcount > 1024*1024) {
|
|
warning("Improbable waitcount %d for proc %d. Corrupt save?", waitcount, _pid);
|
|
return false;
|
|
}
|
|
|
|
_waiting.resize(waitcount);
|
|
for (unsigned int i = 0; i < waitcount; ++i)
|
|
_waiting[i] = rs->readUint16LE();
|
|
|
|
return true;
|
|
}
|
|
|
|
bool Process::validateWaiters() const {
|
|
for (const auto &pid : _waiting) {
|
|
const Process *p = Kernel::get_instance()->getProcess(pid);
|
|
if (!p) {
|
|
// This can happen if a waiting process gets forcibly terminated.
|
|
warning("Invalid procid %d in waitlist for proc %d. Maybe a bug?", pid, _pid);
|
|
} else if (!p->is_suspended()) {
|
|
// This should never happen.
|
|
warning("Procid %d in waitlist for proc %d but not marked suspended", pid, _pid);
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
} // End of namespace Ultima8
|
|
} // End of namespace Ultima
|