2018-11-24 21:39:18 +00:00
|
|
|
/*-
|
2021-01-12 22:16:18 +00:00
|
|
|
* Copyright (c) 2017-2021 Carsten Sonne Larsen <cs@innolan.net>
|
2018-11-24 21:39:18 +00:00
|
|
|
* All rights reserved.
|
|
|
|
*
|
|
|
|
* Redistribution and use in source and binary forms, with or without
|
|
|
|
* modification, are permitted provided that the following conditions
|
|
|
|
* are met:
|
|
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer.
|
|
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
|
|
* documentation and/or other materials provided with the distribution.
|
|
|
|
*
|
|
|
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
|
|
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
|
|
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
|
|
|
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
|
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
|
|
|
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
|
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
|
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
|
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
|
|
|
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
2021-01-12 22:02:29 +00:00
|
|
|
*
|
2018-11-24 21:39:18 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
#include "config.h"
|
2021-01-12 22:02:29 +00:00
|
|
|
#include "global.h"
|
2018-11-24 21:39:18 +00:00
|
|
|
#include "message.h"
|
2021-01-12 22:16:18 +00:00
|
|
|
#include "text.h"
|
2018-11-24 21:39:18 +00:00
|
|
|
#include "mem.h"
|
|
|
|
|
2021-01-12 22:16:18 +00:00
|
|
|
#include <proto/rexxsyslib.h>
|
|
|
|
|
|
|
|
#include "logmod.h"
|
|
|
|
#define MODULENAME "Dispatch"
|
|
|
|
|
|
|
|
struct MsgPort *volatile BrokerPort;
|
|
|
|
struct MsgPort *volatile SyncerPort;
|
|
|
|
struct MsgPort *volatile WindowPort;
|
|
|
|
struct MsgPort *volatile MemoryPort;
|
|
|
|
struct MsgPort *volatile ControlPort;
|
2021-01-31 19:10:59 +00:00
|
|
|
struct MsgPort *volatile ARexxPort;
|
2021-01-12 22:16:18 +00:00
|
|
|
int outstanding;
|
|
|
|
|
|
|
|
static void PublishPort(long, char *);
|
|
|
|
|
|
|
|
void InitMessages(void)
|
|
|
|
{
|
|
|
|
BrokerPort = NULL;
|
|
|
|
SyncerPort = NULL;
|
|
|
|
WindowPort = NULL;
|
|
|
|
MemoryPort = NULL;
|
|
|
|
ControlPort = NULL;
|
2021-01-31 19:10:59 +00:00
|
|
|
ARexxPort = NULL;
|
2021-01-12 22:16:18 +00:00
|
|
|
outstanding = 0;
|
|
|
|
|
|
|
|
CreateMessagePort(MSGPORT_MEMORY);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool SetupPorts(void)
|
|
|
|
{
|
|
|
|
CreateMessagePort(MSGPORT_BROKER);
|
|
|
|
CreateMessagePort(MSGPORT_CONTROL);
|
|
|
|
PublishPort(MSGPORT_CONTROL, CONTROL_PORT_NAME);
|
|
|
|
|
|
|
|
if (RexxSysBase != NULL)
|
|
|
|
{
|
|
|
|
CreateMessagePort(MSGPORT_AREXX);
|
|
|
|
PublishPort(MSGPORT_AREXX, AREXX_PORT_NAME);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (MemoryPort == NULL || BrokerPort == NULL)
|
|
|
|
{
|
|
|
|
LogError("Message port initialization failed");
|
|
|
|
CleanupPorts();
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
LogNotice("Publishing log to message port: %s", LOGGER_PORT_NAME);
|
|
|
|
|
|
|
|
LogTrace("Message port initialization complete");
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void CleanupPorts(void)
|
|
|
|
{
|
|
|
|
DestroyMessagePort(MSGPORT_BROKER);
|
|
|
|
|
|
|
|
if (ControlPort != NULL)
|
|
|
|
{
|
|
|
|
RemPort((struct MsgPort *)ControlPort);
|
|
|
|
DestroyMessagePort(MSGPORT_CONTROL);
|
|
|
|
}
|
|
|
|
|
2021-01-31 19:10:59 +00:00
|
|
|
if (ARexxPort != NULL)
|
2021-01-12 22:16:18 +00:00
|
|
|
{
|
2021-01-31 19:10:59 +00:00
|
|
|
RemPort((struct MsgPort *)ARexxPort);
|
2021-01-12 22:16:18 +00:00
|
|
|
DestroyMessagePort(MSGPORT_AREXX);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (MemoryPort != NULL)
|
|
|
|
{
|
|
|
|
while (outstanding != 0)
|
|
|
|
{
|
|
|
|
WaitPort(MemoryPort);
|
|
|
|
HandleMemoryMessages();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
DestroyMessagePort(MSGPORT_MEMORY);
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct MsgPort *FindMessagePort(long port)
|
|
|
|
{
|
|
|
|
switch (port)
|
|
|
|
{
|
|
|
|
case MSGPORT_BROKER:
|
|
|
|
return (struct MsgPort *)BrokerPort;
|
|
|
|
break;
|
|
|
|
case MSGPORT_SYNCER:
|
|
|
|
return (struct MsgPort *)SyncerPort;
|
|
|
|
break;
|
|
|
|
case MSGPORT_WINDOW:
|
|
|
|
return (struct MsgPort *)WindowPort;
|
|
|
|
break;
|
|
|
|
case MSGPORT_MEMORY:
|
|
|
|
return (struct MsgPort *)MemoryPort;
|
|
|
|
break;
|
|
|
|
case MSGPORT_CONTROL:
|
|
|
|
return (struct MsgPort *)ControlPort;
|
|
|
|
break;
|
|
|
|
case MSGPORT_AREXX:
|
2021-01-31 19:10:59 +00:00
|
|
|
return (struct MsgPort *)ARexxPort;
|
2021-01-12 22:16:18 +00:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
return NULL;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct MsgPort *volatile *FindMessagePortAddress(long port, char **name)
|
2021-01-12 22:02:29 +00:00
|
|
|
{
|
2021-01-12 22:16:18 +00:00
|
|
|
struct MsgPort *volatile *p;
|
|
|
|
char *s;
|
|
|
|
|
|
|
|
switch (port)
|
|
|
|
{
|
|
|
|
case MSGPORT_BROKER:
|
|
|
|
p = &BrokerPort;
|
|
|
|
s = "Broker";
|
|
|
|
break;
|
|
|
|
case MSGPORT_SYNCER:
|
|
|
|
p = &SyncerPort;
|
|
|
|
s = "Synchronizer";
|
|
|
|
break;
|
|
|
|
case MSGPORT_WINDOW:
|
|
|
|
p = &WindowPort;
|
|
|
|
s = "Window";
|
|
|
|
break;
|
|
|
|
case MSGPORT_MEMORY:
|
|
|
|
p = &MemoryPort;
|
|
|
|
s = "Memory";
|
|
|
|
break;
|
|
|
|
case MSGPORT_CONTROL:
|
|
|
|
p = &ControlPort;
|
|
|
|
s = "Control";
|
|
|
|
break;
|
|
|
|
case MSGPORT_AREXX:
|
2021-01-31 19:10:59 +00:00
|
|
|
p = &ARexxPort;
|
2021-01-12 22:16:18 +00:00
|
|
|
s = "ARexx";
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
p = NULL;
|
|
|
|
s = "Unknown";
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
*name = s;
|
|
|
|
return p;
|
2021-01-12 22:02:29 +00:00
|
|
|
}
|
|
|
|
|
2021-01-12 22:16:18 +00:00
|
|
|
static void PublishPort(long port, char *name)
|
2018-11-24 21:39:18 +00:00
|
|
|
{
|
2021-01-12 22:16:18 +00:00
|
|
|
char *s;
|
|
|
|
struct MsgPort *volatile *dest = FindMessagePortAddress(port, &s);
|
|
|
|
if (dest == NULL || *dest == NULL)
|
|
|
|
return;
|
|
|
|
|
|
|
|
struct MsgPort *pub = *dest;
|
|
|
|
pub->mp_Node.ln_Name = name;
|
|
|
|
pub->mp_Node.ln_Pri = 0;
|
|
|
|
|
2018-11-24 21:39:18 +00:00
|
|
|
Forbid();
|
2021-01-12 22:16:18 +00:00
|
|
|
struct MsgPort *msgPort = FindPort((CONST_STRPTR)name);
|
|
|
|
if (msgPort == NULL)
|
2018-11-24 21:39:18 +00:00
|
|
|
{
|
2021-01-12 22:16:18 +00:00
|
|
|
AddPort((struct MsgPort *)pub);
|
2018-11-24 21:39:18 +00:00
|
|
|
}
|
|
|
|
Permit();
|
2021-01-12 22:16:18 +00:00
|
|
|
|
|
|
|
if (msgPort == NULL)
|
|
|
|
LogNotice("%s message port published: %s", s, name);
|
|
|
|
else
|
|
|
|
LogWarn("%s message port is already registered: %s", s, name);
|
|
|
|
}
|
|
|
|
|
|
|
|
struct MsgPort *GetMessagePort(long port)
|
|
|
|
{
|
|
|
|
return FindMessagePort(port);
|
2018-11-24 21:39:18 +00:00
|
|
|
}
|
|
|
|
|
2021-01-12 22:16:18 +00:00
|
|
|
struct Message *GetNewMessage(long port)
|
2018-11-24 21:39:18 +00:00
|
|
|
{
|
2021-01-12 22:16:18 +00:00
|
|
|
struct MsgPort *p = FindMessagePort(port);
|
|
|
|
if (p == NULL)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
return GetMsg(p);
|
|
|
|
}
|
2018-11-24 21:39:18 +00:00
|
|
|
|
2021-01-12 22:16:18 +00:00
|
|
|
ULONG GetPortSignalMask(long port)
|
|
|
|
{
|
|
|
|
struct MsgPort *p = FindMessagePort(port);
|
|
|
|
if (p == NULL)
|
2021-01-12 22:02:29 +00:00
|
|
|
{
|
2021-01-12 22:16:18 +00:00
|
|
|
LogError("Failed to get port signal mask: %ld", port);
|
|
|
|
return 0;
|
2021-01-12 22:02:29 +00:00
|
|
|
}
|
2018-11-24 21:39:18 +00:00
|
|
|
|
2021-01-12 22:16:18 +00:00
|
|
|
return (1 << p->mp_SigBit);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool CreateMessagePort(long port)
|
|
|
|
{
|
|
|
|
struct MsgPort *n = CreateMsgPort();
|
|
|
|
struct MsgPort *volatile *p;
|
|
|
|
bool success = true;
|
|
|
|
char *s;
|
|
|
|
|
|
|
|
p = FindMessagePortAddress(port, &s);
|
|
|
|
if (n != NULL && p != NULL && *p == NULL)
|
2021-01-12 22:02:29 +00:00
|
|
|
{
|
2021-01-12 22:16:18 +00:00
|
|
|
LogTrace(TextPortCreated, s);
|
|
|
|
*p = n;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
LogError(TextPortInitError, s);
|
|
|
|
success = false;
|
2021-01-12 22:02:29 +00:00
|
|
|
}
|
2021-01-12 22:16:18 +00:00
|
|
|
|
|
|
|
return success;
|
2018-11-24 21:39:18 +00:00
|
|
|
}
|
|
|
|
|
2021-01-12 22:16:18 +00:00
|
|
|
void DestroyMessagePort(long port)
|
2018-11-24 21:39:18 +00:00
|
|
|
{
|
2021-01-12 22:16:18 +00:00
|
|
|
struct MsgPort *volatile *p;
|
2021-01-12 22:02:29 +00:00
|
|
|
struct MsgPort *msgPort;
|
|
|
|
bool exist = true;
|
2021-01-12 22:16:18 +00:00
|
|
|
char *s;
|
2018-11-24 21:39:18 +00:00
|
|
|
|
|
|
|
Forbid();
|
2021-01-12 22:16:18 +00:00
|
|
|
p = FindMessagePortAddress(port, &s);
|
|
|
|
if (p == NULL || *p == NULL)
|
2018-11-24 21:39:18 +00:00
|
|
|
{
|
2021-01-12 22:02:29 +00:00
|
|
|
exist = false;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2021-01-12 22:16:18 +00:00
|
|
|
msgPort = *p;
|
|
|
|
*p = NULL;
|
2018-11-24 21:39:18 +00:00
|
|
|
}
|
|
|
|
Permit();
|
2021-01-12 22:02:29 +00:00
|
|
|
|
|
|
|
if (exist)
|
|
|
|
{
|
|
|
|
struct Message *msg;
|
|
|
|
while ((msg = GetMsg(msgPort)))
|
|
|
|
{
|
|
|
|
ReplyMsg(msg);
|
|
|
|
}
|
|
|
|
DeleteMsgPort(msgPort);
|
2021-01-12 22:16:18 +00:00
|
|
|
LogTrace(TextPortCleaned, s);
|
2021-01-12 22:02:29 +00:00
|
|
|
}
|
2021-01-12 22:16:18 +00:00
|
|
|
else
|
|
|
|
{
|
|
|
|
LogError(TextPortNotFound, s);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Send an application message in a safe manner.
|
|
|
|
*/
|
|
|
|
static void SendAppMessage(long port, long type)
|
|
|
|
{
|
|
|
|
struct MsgPort *dest, *reply;
|
|
|
|
bool sent = false;
|
|
|
|
|
|
|
|
struct ApplicationMesage *msg = AllocStructSafe(struct ApplicationMesage);
|
|
|
|
if (msg == NULL)
|
|
|
|
return;
|
|
|
|
|
|
|
|
msg->Msg.mn_Node.ln_Type = NT_MESSAGE;
|
|
|
|
msg->Msg.mn_Length = sizeof(struct ApplicationMesage);
|
|
|
|
msg->MsgType = MSGTYPE_APP;
|
|
|
|
msg->MsgId = type;
|
|
|
|
|
|
|
|
Forbid();
|
|
|
|
dest = FindMessagePort(port);
|
|
|
|
reply = (struct MsgPort *)MemoryPort;
|
|
|
|
if (dest != NULL && reply != NULL)
|
|
|
|
{
|
|
|
|
msg->Msg.mn_ReplyPort = reply;
|
|
|
|
PutMsg(dest, (struct Message *)msg);
|
|
|
|
outstanding++;
|
|
|
|
sent = true;
|
|
|
|
}
|
|
|
|
Permit();
|
|
|
|
|
|
|
|
if (!sent)
|
|
|
|
FreeMemSafe(msg);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Send a message to the broker.
|
|
|
|
*/
|
|
|
|
void SendBrokerMessage(long type)
|
|
|
|
{
|
|
|
|
SendAppMessage(MSGPORT_BROKER, type);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Send a message to the settings window.
|
|
|
|
*/
|
|
|
|
void SendWindowMessage(long type)
|
|
|
|
{
|
|
|
|
SendAppMessage(MSGPORT_WINDOW, type);
|
2018-11-24 21:39:18 +00:00
|
|
|
}
|
|
|
|
|
2021-01-12 22:16:18 +00:00
|
|
|
/*
|
|
|
|
* Try to send a message to the logger message port.
|
|
|
|
*/
|
|
|
|
void SendLogMessage(struct LogMessage *msg)
|
|
|
|
{
|
|
|
|
struct MsgPort *port, *reply;
|
|
|
|
bool sent = false;
|
|
|
|
|
|
|
|
msg->AppMsg.Msg.mn_Node.ln_Type = NT_MESSAGE;
|
|
|
|
msg->AppMsg.Msg.mn_Length = sizeof(struct LogMessage);
|
|
|
|
msg->AppMsg.MsgType = MSGTYPE_LOG;
|
|
|
|
|
|
|
|
Forbid();
|
|
|
|
reply = (struct MsgPort *)MemoryPort;
|
|
|
|
port = FindPort((CONST_STRPTR)LOGGER_PORT_NAME);
|
|
|
|
if (port != NULL && reply != NULL)
|
|
|
|
{
|
|
|
|
msg->AppMsg.Msg.mn_ReplyPort = reply;
|
|
|
|
PutMsg(port, (struct Message *)msg);
|
|
|
|
outstanding++;
|
|
|
|
sent = true;
|
|
|
|
}
|
|
|
|
Permit();
|
|
|
|
|
|
|
|
if (!sent && port != NULL)
|
|
|
|
{
|
|
|
|
// Try again using own reply port
|
|
|
|
struct MsgPort *replyPort = CreateMsgPort();
|
|
|
|
if (replyPort != NULL)
|
|
|
|
{
|
|
|
|
Forbid();
|
|
|
|
port = FindPort((CONST_STRPTR)LOGGER_PORT_NAME);
|
|
|
|
if (port != NULL)
|
|
|
|
{
|
|
|
|
msg->AppMsg.Msg.mn_ReplyPort = replyPort;
|
|
|
|
PutMsg(port, (struct Message *)msg);
|
|
|
|
sent = true;
|
|
|
|
}
|
|
|
|
Permit();
|
|
|
|
|
|
|
|
WaitPort(replyPort);
|
|
|
|
GetMsg(replyPort);
|
|
|
|
DeleteMsgPort(replyPort);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!sent)
|
|
|
|
FreeVec(msg);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Free processed messages.
|
|
|
|
*/
|
|
|
|
void HandleMemoryMessages(void)
|
|
|
|
{
|
|
|
|
struct ApplicationMesage *msg;
|
|
|
|
while ((msg = (struct ApplicationMesage *)GetMsg(MemoryPort)))
|
|
|
|
{
|
|
|
|
if (msg->MsgType == MSGTYPE_LOG)
|
|
|
|
{
|
|
|
|
FreeVec(msg);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
FreeMemSafe(msg);
|
|
|
|
}
|
|
|
|
outstanding--;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Send a message and wait for the reply.
|
|
|
|
*/
|
|
|
|
void SendMessageWait(long port, long type)
|
|
|
|
{
|
|
|
|
struct MsgPort *replyPort = CreateMsgPort();
|
|
|
|
if (replyPort != NULL)
|
|
|
|
{
|
|
|
|
struct ApplicationMesage *message = AllocStructSafe(struct ApplicationMesage);
|
|
|
|
if (message != NULL)
|
|
|
|
{
|
|
|
|
message->Msg.mn_Node.ln_Type = NT_MESSAGE;
|
|
|
|
message->Msg.mn_Length = sizeof(struct ApplicationMesage);
|
|
|
|
message->Msg.mn_ReplyPort = replyPort;
|
|
|
|
message->MsgType = MSGTYPE_APP;
|
|
|
|
message->MsgId = type;
|
|
|
|
|
|
|
|
Forbid();
|
|
|
|
struct MsgPort *dest = FindMessagePort(port);
|
|
|
|
if (dest != NULL)
|
|
|
|
{
|
|
|
|
PutMsg(dest, (struct Message *)message);
|
|
|
|
}
|
|
|
|
Permit();
|
|
|
|
|
|
|
|
if (dest != NULL)
|
|
|
|
{
|
|
|
|
WaitPort(replyPort);
|
|
|
|
GetMsg(replyPort);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
LogTrace("Message port is closed");
|
|
|
|
}
|
|
|
|
|
|
|
|
FreeMemSafe(message);
|
|
|
|
}
|
|
|
|
DeleteMsgPort(replyPort);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Process any remaining messages and close port cleanly.
|
|
|
|
*/
|
2021-01-12 22:02:29 +00:00
|
|
|
void CleanupMsgPort(struct MsgPort **port)
|
2018-11-24 21:39:18 +00:00
|
|
|
{
|
2021-01-12 22:02:29 +00:00
|
|
|
struct Message *msg;
|
|
|
|
struct MsgPort *msgPort = *port;
|
|
|
|
|
|
|
|
if (*port == NULL)
|
2018-11-24 21:39:18 +00:00
|
|
|
{
|
2021-01-12 22:02:29 +00:00
|
|
|
return;
|
2018-11-24 21:39:18 +00:00
|
|
|
}
|
2021-01-12 22:02:29 +00:00
|
|
|
|
|
|
|
*port = NULL;
|
|
|
|
|
|
|
|
while ((msg = GetMsg(msgPort)))
|
|
|
|
{
|
|
|
|
ReplyMsg(msg);
|
|
|
|
}
|
|
|
|
|
|
|
|
DeleteMsgPort(msgPort);
|
2018-11-24 21:39:18 +00:00
|
|
|
}
|