mirror of
https://github.com/libretro/scummvm.git
synced 2025-04-02 14:51:40 +00:00
245 lines
6.4 KiB
C++
245 lines
6.4 KiB
C++
/* ScummVM - Scumm Interpreter
|
|
* Copyright (C) 2002 The ScummVM project
|
|
*
|
|
* 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 2
|
|
* 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, write to the Free Software
|
|
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
*
|
|
* $Header$
|
|
*/
|
|
|
|
#include "stdafx.h"
|
|
#include "engine.h"
|
|
|
|
#include <exec/memory.h>
|
|
#include <exec/semaphores.h>
|
|
#include <dos/dostags.h>
|
|
#include <emul/emulinterface.h>
|
|
|
|
#include <proto/exec.h>
|
|
#include <proto/dos.h>
|
|
#include <proto/timer.h>
|
|
|
|
#include "morphos.h"
|
|
#include "timer.h"
|
|
|
|
static TagItem TimerServiceTags[] = { { NP_Entry, 0 },
|
|
{ NP_Name, (ULONG)"ScummVM Timer Service" },
|
|
{ NP_Priority, 20 },
|
|
{ TAG_DONE, 0 }
|
|
};
|
|
|
|
Timer::Timer(Engine * engine)
|
|
{
|
|
static EmulFunc ThreadEmulFunc;
|
|
|
|
InitSemaphore(&TimerServiceSemaphore);
|
|
|
|
ThreadEmulFunc.Trap = TRAP_FUNC;
|
|
ThreadEmulFunc.Address = (ULONG) &TimerService;
|
|
ThreadEmulFunc.StackSize = 16000;
|
|
ThreadEmulFunc.Extension = 0;
|
|
ThreadEmulFunc.Arg1 = (ULONG) this;
|
|
ThreadEmulFunc.Arg2 = (ULONG) engine;
|
|
TimerServiceTags[0].ti_Data = (ULONG) &ThreadEmulFunc;
|
|
TimerServiceThread = CreateNewProc(TimerServiceTags);
|
|
}
|
|
|
|
Timer::~Timer()
|
|
{
|
|
if (TimerServiceThread)
|
|
{
|
|
Signal((Task *) TimerServiceThread, SIGBREAKF_CTRL_C);
|
|
ObtainSemaphore(&TimerServiceSemaphore);
|
|
ReleaseSemaphore(&TimerServiceSemaphore);
|
|
}
|
|
}
|
|
|
|
bool Timer::init()
|
|
{
|
|
return TimerServiceThread != NULL;
|
|
}
|
|
|
|
void Timer::release()
|
|
{
|
|
}
|
|
|
|
bool Timer::installProcedure(TimerProc procedure, int32 interval)
|
|
{
|
|
return SendMsg(TSM_MSGID_ADDTIMER, procedure, interval);
|
|
}
|
|
|
|
void Timer::releaseProcedure(TimerProc procedure)
|
|
{
|
|
SendMsg(TSM_MSGID_REMTIMER, procedure, 0);
|
|
}
|
|
|
|
bool Timer::SendMsg(ULONG msg_id, TimerProc procedure, LONG interval)
|
|
{
|
|
if (TimerServiceThread == NULL)
|
|
return false;
|
|
|
|
TimerServiceMessage *tmsg = (TimerServiceMessage *) AllocVec(sizeof (TimerServiceMessage), MEMF_PUBLIC | MEMF_CLEAR);
|
|
if (tmsg == NULL)
|
|
return false;
|
|
|
|
MsgPort *reply_port = CreateMsgPort();
|
|
if (reply_port == NULL)
|
|
{
|
|
FreeVec(tmsg);
|
|
return false;
|
|
}
|
|
|
|
tmsg->tsm_Message.mn_Node.ln_Type = NT_MESSAGE;
|
|
tmsg->tsm_Message.mn_ReplyPort = reply_port;
|
|
tmsg->tsm_Message.mn_Length = sizeof (TimerServiceMessage);
|
|
tmsg->tsm_MsgID = msg_id;
|
|
tmsg->tsm_Callback = procedure;
|
|
tmsg->tsm_Interval = interval;
|
|
PutMsg(&TimerServiceThread->pr_MsgPort, tmsg);
|
|
WaitPort(reply_port);
|
|
GetMsg(reply_port);
|
|
|
|
FreeVec(tmsg);
|
|
DeleteMsgPort(reply_port);
|
|
|
|
return true;
|
|
}
|
|
|
|
void Timer::TimerService(Timer *this_ptr, Engine *engine)
|
|
{
|
|
MsgPort *port = &((Process *) FindTask(NULL))->pr_MsgPort;
|
|
ULONG port_bit = 1 << port->mp_SigBit;
|
|
ULONG signal_mask = SIGBREAKF_CTRL_C | port_bit;
|
|
ULONG timer_bits = 0, signals;
|
|
ULONG interval, t;
|
|
timeval start_callback, end_callback;
|
|
|
|
ULONG timers = 0;
|
|
TimerSlot timer_slots[MAX_TIMERS];
|
|
|
|
ObtainSemaphore(&this_ptr->TimerServiceSemaphore);
|
|
|
|
for (;;)
|
|
{
|
|
signals = Wait(signal_mask);
|
|
|
|
GetSysTime(&start_callback);
|
|
|
|
if (signals & port_bit)
|
|
{
|
|
TimerServiceMessage *tmsg;
|
|
|
|
while (tmsg = (TimerServiceMessage *) GetMsg(port))
|
|
{
|
|
if (tmsg->tsm_Message.mn_Length == sizeof (TimerServiceMessage))
|
|
{
|
|
switch (tmsg->tsm_MsgID)
|
|
{
|
|
case TSM_MSGID_ADDTIMER:
|
|
if (timers < MAX_TIMERS)
|
|
{
|
|
ULONG unit = UNIT_MICROHZ;
|
|
|
|
if (tmsg->tsm_Interval > 1000)
|
|
unit = UNIT_VBLANK;
|
|
if (OSystem_MorphOS::OpenATimer(&timer_slots[timers].ts_Port, (IORequest **) &timer_slots[timers].ts_IORequest, unit))
|
|
{
|
|
timer_slots[timers].ts_Callback = tmsg->tsm_Callback;
|
|
timer_slots[timers].ts_Interval = tmsg->tsm_Interval;
|
|
timer_slots[timers].ts_SignalBit = 1 << timer_slots[timers].ts_Port->mp_SigBit;
|
|
|
|
signal_mask |= timer_slots[timers].ts_SignalBit;
|
|
timer_bits |= timer_slots[timers].ts_SignalBit;
|
|
|
|
timerequest *req = timer_slots[timers].ts_IORequest;
|
|
interval = timer_slots[timers].ts_Interval;
|
|
req->tr_node.io_Command = TR_ADDREQUEST;
|
|
req->tr_time.tv_secs = interval/1000;
|
|
req->tr_time.tv_micro = (interval%1000)*1000;
|
|
SendIO(req);
|
|
|
|
timers++;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case TSM_MSGID_REMTIMER:
|
|
{
|
|
for (t = 0; t < timers; t++)
|
|
{
|
|
if (timer_slots[t].ts_Callback == tmsg->tsm_Callback)
|
|
{
|
|
AbortIO((IORequest *) timer_slots[t].ts_IORequest);
|
|
WaitIO((IORequest *) timer_slots[t].ts_IORequest);
|
|
signal_mask &= ~timer_slots[t].ts_SignalBit;
|
|
timer_bits &= ~timer_slots[t].ts_SignalBit;
|
|
DeleteIORequest((IORequest *) timer_slots[t].ts_IORequest);
|
|
DeleteMsgPort(timer_slots[t].ts_Port);
|
|
if (t < timers-1)
|
|
memmove(&timer_slots[t], &timer_slots[t+1], sizeof (TimerSlot)*(timers-t-1));
|
|
timers--;
|
|
continue;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
default:
|
|
warning("MorphOS TimerService received message of unknown type.");
|
|
}
|
|
}
|
|
|
|
ReplyMsg((Message *) tmsg);
|
|
}
|
|
}
|
|
|
|
if (signals & SIGBREAKF_CTRL_C)
|
|
break;
|
|
|
|
if (signals & timer_bits)
|
|
{
|
|
for (t = 0; t < timers; t++)
|
|
{
|
|
if (signals & timer_slots[t].ts_SignalBit)
|
|
{
|
|
timerequest *req = timer_slots[t].ts_IORequest;
|
|
WaitIO((IORequest *) req);
|
|
interval = timer_slots[t].ts_Interval;
|
|
(*timer_slots[t].ts_Callback)(engine);
|
|
GetSysTime(&end_callback);
|
|
SubTime(&end_callback, &start_callback);
|
|
interval -= end_callback.tv_sec*1000+end_callback.tv_micro/1000+40;
|
|
|
|
req->tr_node.io_Command = TR_ADDREQUEST;
|
|
req->tr_time.tv_secs = interval/1000;
|
|
req->tr_time.tv_micro = (interval%1000)*1000;
|
|
SendIO(req);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
for (t = 0; t < timers; t++)
|
|
{
|
|
AbortIO((IORequest *) timer_slots[t].ts_IORequest);
|
|
WaitIO((IORequest *) timer_slots[t].ts_IORequest);
|
|
DeleteIORequest((IORequest *) timer_slots[t].ts_IORequest);
|
|
DeleteMsgPort(timer_slots[t].ts_Port);
|
|
}
|
|
|
|
ReleaseSemaphore(&this_ptr->TimerServiceSemaphore);
|
|
RemTask(NULL);
|
|
}
|
|
|