amiga-sources@sugar.uu.net (alt.sources.amiga) (09/11/88)
Archive: uunet!~uucp/amiga-sources/ipc.src.Z
:
#! /bin/sh
# This is a shell archive, created on Sugar Land Unix (..!uunet!sugar)
# by amiga-sources (alt.sources.amiga) on Sun Sep 11 08:16:06 1988
# Remove anything before the "#! /bin/sh" line, then unpack it by saving
# it into a file and typing "sh file". If you do not have sh, you need
# unshar, a dearchiving program which is widely available. In the absolute
# wost case, you can crack the files out by hand.
# If the archive is complete, you will see the message "End of archive."
# at the end.
# This archive contains the following files...
# 'READ_ME'
# 'IPC.h'
# 'IPCPorts.h'
# 'IPC.c'
# 'LoadIPCPort.c'
# 'Broker.c'
# 'Broker.lnk'
# To extract them, run the following through /bin/sh
echo x - READ_ME
sed 's/^X//' > READ_ME << '//END_OF_FILE'
X
X IPC System Sources
X ==================
X
XThis directory contains the C source files for all the current system
Xmodules of IPC.
X
XInclude header files:
X
X IPC.h -- contains definitions for all standard IPC functions.
X Should be included in any source that uses IPC.
X
X IPCPorts.h -- Port structure and flags. Should only be needed
X in special cases: normally all access to IPCPorts
X should be via the procedures in IPC.c (and perhaps
X LoadIPCPort.c) -- IPCPorts are then just defined for
X the user as standard MsgPorts. If needed, IPCPorts.h
X should precede IPC.h.
X
XSource Files:
X
X IPC.c -- Contains all the basic IPC procedures that a user
X program will call for managing IPCPorts and
X IPCMessages. The object file generated from this
X source by your compiler should be linked between your
X user program and the C libraries.
X
X LoadIPCPort.c -- An alternative to GetIPCPort (which it uses
X internally) that sends a message to a "Port Broker"
X if the requested port does not currently have a server;
X if the broker cannot find a server to satisfy the
X request, this call will return NULL. If used, link
X this module's object file before IPC itself.
X
X Broker.c -- A skeletal Port Broker. This is just a demonstration
X of how a broker will accept messages and reply to them;
X it does nothing about actually trying to locate a
X server -- just posts a courteous request to the user in
X its console window... It is written so that it should
X be easy to plug in a proper loading procedure. Comments
X are sparse [apologies!] but the code is probably
X compact enough to be followed fairly easily.
X
XLink File:
X
X Broker.lnk -- A BLink "WITH" file to create an exectuable version
X of the broker.
X
X +++++++++++++++++
X
XCompatibility:
X
X The header files and IPC.c should be totally compatible with both
X Lattice and Manx/Aztec [with thanks to Brian Witt for the conversion!].
X I think LoadIPCPort probably is, but will make no guarantees (it DOES
X work with Lattice!); the Broker code will probably need some tweaking
X to work with Manx.
X
X Of COURSE there should be no problems in sending IPCMessages between
X modules compiled under different regimes!
X
XCompiling under Lattice:
X
X Any compiler switches you use are optional, but I normally compile with
X the -v switch to suppress stack checking, and use the default
X addressing mode (Base Register Relative in 4.0+). If you are going to
X call this code from a child task of the main program, you MUST of
X course use -v, and you will normally need -y as well (see the Lattice
X manual).
X
X +++++++++++++++++
X -----------------
X
X
//END_OF_FILE
echo x - IPC.h
sed 's/^X//' > IPC.h << '//END_OF_FILE'
X/*******************************************************************
X * *
X * IPC.h *
X * *
X * Inter-Process-Communication Message Format *
X * *
X * Revision 1.2.1 -- 1988 July 31 *
X * *
X * Copyright 1988 Peter da Silva & Peter Goodeve *
X * All Rights reserved *
X * *
X * This source is freely distributable, but should not be *
X * modified without prior consultation with the authors. *
X * *
X *******************************************************************/
X
X#ifdef AZTEC_C
X/* can't use prototyping */
X#define NARGS 1
X/* (if NARGS is undefined, prototyping is enabled) */
X#endif
X
X#ifndef EXEC_TYPES_H
X#include "exec/types.h"
X#endif
X
X#ifndef EXEC_PORTS_H
X#include "exec/ports.h"
X#endif
X
X/*** Item Reference block -- an arbitrary number of these may be
X put in an IPCMessage ***/
X
Xstruct IPCItem {
X ULONG ii_Id; /* four character ID (normally);
X determines exact meaning of IPCItem IDs */
X ULONG ii_Flags; /* upper 16 bits have standard meaning;
X lower 16 bits are message dependent */
X ULONG ii_Size; /* size of data structure (zero if ii_Ptr is not
X actually a pointer to data) */
X void *ii_Ptr; /* points to defined data structure (could be within
X message block if IE_Flags says so) -- also may be
X recast to other 32-bit value (e.g. Lock) */
X };
X
X
X
X/*** The basic IPCMessage block ***/
X
Xstruct IPCMessage {
X struct Message ipc_Msg;
X /* ..ln_Name field should be NULL
X mn_Length will include IPC_Items array and any in-line data
X */
X ULONG ipc_Id, /* four character (or other) ID */
X ipc_Flags;
X UWORD ipc_ItemCount; /* number of items in array */
X struct IPCItem ipc_Items[1]; /* .. actual size as needed */
X };
X
X
X/*************************************************************/
X
X/* Flags set by client (tentative...): */
X/* -- may appear in either IPCItem or IPCMessage Flags field */
X
X#define IPC_TRANSFER 0x08000000
X /* Data block ownership is to be transferred to receiver. */
X#define IPC_NETWORK 0x04000000
X /* The data in this block/message may be transmitted to
X another machine */
X#define IPC_INMESSAGE 0x02000000
X /* The data in this block/message is included in the message length */
X
X/* Flags returned by server (ditto): */
X
X#define IPC_NOTKNOWN 0x80000000
X /* The server could not handle this block/message
X (either because it did not understand the ID or
X was unable to process it -- see the secondary flags */
X#define IPC_MODIFIED 0x40000000
X /* The server modified the data, either within the
X supplied data block(s) or -- if permitted -- by
X replacing/removing the block pointer; again maybe
X other flag bits should indicate the nature of
X the modification */
X
X/* valid for Item only: */
X#define IPC_SERVER_OWNED 0x10000000
X /* The server owns this data Item -- either because it has
X created it or because it took it over from the client
X (in which case it clears IPC_TRANSFER, which must have
X been set) */
X
X
X/* secondary flag bits (more to come...): */
X
X#define IPC_CHECKITEM 0x00800000
X /* associated with IPC_NOTKNOWN -- indicates that one or more
X particular items caused the flag to be set */
X#define IPC_FAILED 0x00400000
X /* IPC_NOTKNOWN flag was set because the server failed to
X handle an ID that it is designed to (rather than just
X not recognizing the block) */
X
X/*************************************************************/
X
X
X/*** IPC Ports and Procedures ***/
X
X
X/* -- see IPCPorts.h for actual structure definitions */
X#ifndef IPC_PORTS_H
X/* Normal user doesn't need access to port components,
X so just use a convenient define. Note that an IPC port
X is NEVER in private data space -- or in the public port
X list -- it is created and managed by the package routines
X only. */
X#define IPCPort MsgPort
X#endif
X
X
X/* IPC Port Handling function prototypes: */
X
X#ifndef NARGS /* define this to SUPPRESS function argument prototyping */
X
Xstruct IPCPort * FindIPCPort(char *);
X /* returns pointer to port if it exists -- null otherwise;
X registers a new connection to the port */
X
Xstruct IPCPort * GetIPCPort(char *);
X /* returns pointer to port -- it is created if it doesn't exist;
X registers a new connection to the port */
X
X
Xvoid UseIPCPort(struct IPCPort *);
X /* adds a connection to a port (passed by pointer from another
X process) */
X
X
Xvoid DropIPCPort(struct IPCPort *);
X /* disconnect from port -- port will be destroyed if there are
X no other connections left */
X
X
Xstruct IPCPort * ServeIPCPort(char *);
X /* become a server for the named port (created if it doesn't exist);
X null is returned if the port already has a server, otherwise a
X pointer to it is returned */
X
Xvoid ShutIPCPort(struct IPCPort *);
X /* (server only) prevent more messages being sent to this port, but
X do not end server connection; remaining messages can be dealt
X with before Leaving */
X
Xvoid LeaveIPCPort(struct IPCPort *);
X /* cease to be a server for this port; another process can then
X become a server if it desires */
X
XCheckIPCPort(struct IPCPort *, UWORD);
X /* returns number of current connections to this port (including
X server); a call by the server (only) will also set the (user
X settable) port flags to the value in the second argument --
X currently the only valid flag is IPP_NOTIFY */
X
X
XPutIPCMsg(struct IPCPort *, struct IPCMessage *);
X /* sends an IPCMessage to an IPCPort; if the port has no server or
X is shut, the message is not sent and the function returns FALSE;
X otherwise it returns TRUE. (Other port flags to be added later
X may affect these actions.) */
X
Xstruct IPCMessage * CreateIPCMsg(int, int, struct MsgPort *);
X /* creates a standard IPCMessage block (in MEMF_PUBLIC) with the
X number of IPCItems supplied as first argument; the second
X argument is the number of bytes -- if any -- to reserve beyond
X that required for the items; the third is a pointer to the
X ReplyPort (may be NULL -- note that it's a standard MsgPort,
X not an IPCPort). (You always have to manage any data
X blocks yourself). */
X
X
Xvoid DeleteIPCMsg(struct IPCMessage *);
X /* deletes a standard IPCMessage block; you must first have disposed
X of any attached data as appropriate */
X
X/*************************************************************/
X#else NARGS defined
X
Xstruct IPCPort * FindIPCPort ();
Xstruct IPCPort * GetIPCPort ();
Xvoid UseIPCPort ();
Xvoid DropIPCPort ();
Xstruct IPCPort * ServeIPCPort ();
Xvoid ShutIPCPort ();
Xvoid LeaveIPCPort ();
Xint CheckIPCPort ();
Xint PutIPCMsg ();
Xstruct IPCMessage * CreateIPCMsg ();
Xvoid DeleteIPCMsg ();
X
X/*************************************************************/
X#endif NARGS
X
X
X/* System IPCPort flags: */
X
X#define IPP_SERVED 0x8000
X /* port currently has a server */
X#define IPP_SHUT 0x4000
X /* port is no longer open for new messages (server still attached) */
X#define IPP_REOPEN 0x2000
X /* set (by "Port Broker") to request that server reopen service
X to this port after it has completed Shut/Leave sequence
X in progress */
X#define IPP_LOADING 0x1000
X /* set (by "Port Broker") to indicate that a server is being loaded
X for this port (cleared by ServeIPCPort()) */
X
X
X/* Server settable Port flags: */
X
X#define IPP_NOTIFY 0x0001
X /* server wants to be signalled if connection is added or
X dropped (the port sigbit is used to signal the task,
X but no message is sent) */
X
X/*************************************************************/
X
X/*
X * Some useful Macros:
X */
X
X#define GetIPCMessage(port) ((struct IPCMessage *)GetMsg((struct MsgPort *)port))
X
X#define ReplyIPCMessage(msg) ReplyMsg((struct Message *)msg)
X
X#define SigBitIPCPort(port) (1<<((struct MsgPort *)port)->mp_SigBit)
X /* note: this will work whether or not IPCPorts.h has been included */
X
X
X/*
X For convenience in creating IDs:
X (Alternatively, your compiler may have multi-character constants,
X which you may find more convenient (but less portable...))
X*/
X
X#define MAKE_ID(a,b,c,d) ((a)<<24L | (b)<<16L | (c)<<8 | (d))
X
X
//END_OF_FILE
echo x - IPCPorts.h
sed 's/^X//' > IPCPorts.h << '//END_OF_FILE'
X#ifndef IPC_PORTS_H
X#define IPC_PORTS_H
X
X/*** include this BEFORE IPC.H (if required) ***/
X
X/*******************************************************************
X * *
X * IPCPorts.h *
X * *
X * Inter-Process-Communication Port Format *
X * *
X * Release 1.2 -- 1988 July 22 *
X * *
X * Copyright 1988 Peter Goodeve *
X * *
X * This source is freely distributable, and may be used freely *
X * in any program, but the structures should not be modified *
X * without prior consultation with the author. (This is just to * *
X * prevent proliferation of incompatible variants. Don't be *
X * inhibited from suggesting enhancements!) *
X * *
X *******************************************************************/
X/*******************************************************************
X * *
X * 88:7:22 ipp_BrokerInfo added to IPCPort *
X * *
X *******************************************************************/
X
X#ifndef EXEC_TYPES_H
X#include "exec/types.h"
X#endif
X
X#ifndef EXEC_PORTS_H
X#include "exec/ports.h"
X#endif
X
X/*******************************************************************
X * *
X * IPC Ports are essentially standard Exec message Ports except *
X * for added fields to keep track of their usage. Also they *
X * are kept on their own list. *
X * *
X * Note that the port name has to be kept WITHIN the structure *
X * also, as the process that created it may go away. The size *
X * field holds the size of the structure including the name, so *
X * it may be deleted safely when no longer needed. *
X * *
X *******************************************************************/
X
Xstruct IPCPort {
X struct MsgPort ipp_Port;
X ULONG ipp_Id; /* for future use */
X UWORD ipp_UseCount, /* number of connections to the port */
X ipp_Flags, /* internal information */
X ipp_Size; /* size of the WHOLE structure */
X void * ipp_Broker_Info; /* pointer to private information */
X char ipp_Name[1]; /* where name is actually kept! */
X };
X
X
X/* ipp_Flags -- defined in IPC.h: */
X
X/***********************************
X#define IPP_SERVED 0x8000
X#define IPP_SHUT 0x4000
X#define IPP_REOPEN 0x2000
X#define IPP_LOADING 0x1000
X
X#define IPP_NOTIFY 0x0001
X***********************************/
X
X#define IPP_SERVER_FLAGS 0x00FF
X
X
X
X/*******************************************************************
X * *
X * Only one IPCBasePort structure will exist in the system. *
X * It is the only IPC Port on the public Exec port list, and *
X * has the standard name "IPC_Base_Port". (Note that the name *
X * string begins in the last location of the IPCPort structure; *
X * "moreName" is just to provide the necessary space, so the *
X * list header begins at a defined offset.) *
X * *
X *******************************************************************/
X
Xstruct IPCBasePort {
X struct IPCPort ipcb_Port; /* used to place in public Port list */
X /* also will be public port for a Broker */
X char moreName[20]; /* enough space for name */
X struct List ipcb_PortList; /* List of current IPCPorts */
X };
X
X/*******************************************************************/
X
X#endif
X
//END_OF_FILE
echo x - IPC.c
sed 's/^X//' > IPC.c << '//END_OF_FILE'
X/*******************************************************************
X * *
X * IPC.c *
X * *
X * Inter-Process-Communication Procedures *
X * *
X * Release 1.2 -- 1988 July 22 *
X * *
X * Copyright 1988 Peter Goodeve *
X * *
X * This source is freely distributable, and may be used freely *
X * in any program, but its functionality should not be modified *
X * without prior consultation with the author. (This is just to * *
X * prevent proliferation of incompatible variants. Don't be *
X * inhibited from suggesting enhancements!) *
X * *
X *******************************************************************/
X
X/*******************************************************************
X * *
X * Modification History: *
X * *
X * 88:7:22 PutIPCPort accepts IPP_LOADING flag *
X * *
X * 88:7:11 Manx/Aztec compatibility added *
X * CheckIPCPort now has flag return option *
X * FindIPCPort now fails if no server *
X * CreateIPCMsg has two added args *
X * *
X * *
X *******************************************************************/
X
X/********************************************************************
X * *
X * Synopsis of usage: *
X * ======== *
X * *
X * Client: *
X * *
X * port = GetIPCPort(name); *
X * or port = FindIPCPort(name) *
X * ..... *
X * msg = CreateIPCMsg(nitems, nxbytes, replyport); *
X * ..... *
X * PutIPCMsg(port,msg); *
X * ..... *
X * DeleteIPCMsg(msg); *
X * ..... *
X * DropIPCPort(port); *
X * *
X * Server: [standard Exec procedures in brackets] *
X * *
X * port = ServeIPCPort(name); *
X * ..... *
X * [WaitPort(port); or Wait(sigbits);] *
X * ..... *
X * [msg = GetMsg(port);] *
X * ..... *
X * [ReplyMsg(msg);] *
X * ..... *
X * ShutIPCPort(port); *
X * <handle remaining messages on the port> *
X * LeaveIPCPort(port); *
X * *
X * Misc.: *
X * *
X * UseIPCPort(port); *
X * CheckIPCPort(port,flags); *
X * *
X * *
X ********************************************************************/
X
X/********************************************************************
X * *
X * These procedures provide a mechanism for independent processes *
X * to communicate with each other through "IPC ports". These are *
X * similar to standard Exec Message Ports, except that they are *
X * not "owned" by any of the processes; any one process can *
X * declare itself a "server" (provided no other is currently *
X * claiming this right), and thus becomes temporarily the handler *
X * of messages passed to this port. If there is no server, any *
X * attempt to send a message to a port will return failure, and *
X * the client may take whatever action is appropriate. A client *
X * may safely "Get" a pointer to a named port (even if there is no *
X * server yet) and can rely on it remaining valid until it "Drops" *
X * it again. (In contrast to Exec ports, which have no such *
X * protection.) *
X * *
X * IPC Ports don't appear in the Exec named port list -- they have *
X * their own. There is a single publicly available name, itself *
X * actually a port on the public list (for reasons we'll see later) *
X * to which is added some data structure including the IPC Port *
X * list. *
X * *
X * These procedures are just one part of a fully developed system. *
X * (Another is the IPCMessage structure itself -- see IPC.h and *
X * elsewhere -- which is essentially independent of the IPC Port *
X * mechanism.) They form a fairly self contained set, so they've *
X * initially been written as a single source file, but there's no *
X * reason they couldn't be split into smaller segments. Their *
X * natural home is a resident library in any case, but that can *
X * wait for the moment. *
X * *
X * Other modules will doubtless have to be added. One such is *
X * "LoadIPCPort(name)" which, after doing a GetIPCPort(), will *
X * check the returned port to see if it has a server; if not, it *
X * will check to see if there is a "broker" process serving the *
X * IPCBasePort, and if so will send a message to that asking for *
X * the port to be "served". (The broker is essentially a server *
X * like any other -- it will probably look up the port in a user *
X * supplied list and load the specified server; more advanced *
X * models may check to see if the server is on another machine, *
X * for example.) *
X * - - - - - - - - - - - *
X * *
X * This code has only been tested under Lattice 4.0. It is *
X * intended to be compiler independent, but please check it *
X * for problems. The code is not always optimized! *
X * - - - - - - - - - - - *
X * *
X * %% Modified to work with Manx 16-bit integer model %% *
X * %% 25-june-88 by brian witt %% *
X * - - - - - - - - - - - *
X * *
X * %% The fundamental concept of keeping a use-count %% *
X * %% on a port is due to Matt Dillon. Thanks Matt! %% *
X * *
X ********************************************************************/
X
X
X#include "IPCPorts.h"
X /* this should be included first to suppress defaults in IPC.h */
X /* other modules in processes using IPC will not usually need
X this header -- only IPC.h */
X
X#include "IPC.h"
X /* note -- the above includes prototypes for the procedures below */
X
X#include "exec/memory.h"
X#include "exec/tasks.h"
X
X#define SOL(s) ((LONG)sizeof(s))
X
X/* individual function declarations, so we don't need #ifdefs
X (replace these if you like with a suitable #include for your compiler
X -- e.g. proto/exec.h for Lattice 4.0, functions.h for Manx) */
X
Xextern struct Task * FindTask();
Xextern struct MsgPort * FindPort();
Xextern struct Node * FindName();
Xextern APTR AllocMem();
Xextern LONG AllocSignal();
X
X
X
X/*
X * IPCBasePort is the node around which the whole IPC system is organized.
X * It is placed in AmigaExec's public port list by the first program to
X * use IPC, and remains there ever after. It is the ONLY public port
X * created by the IPC system -- all IPCPorts are hung on a list from a
X * header in the IPCBasePort structure. It may also be an actual port
X * served by a "broker" process, which will be sent messages requesting,
X * for example, that it load a server for a port.
X */
X
Xstruct IPCBasePort *IPCBasePort = NULL;
X
X
X/*
X * OpenIPCBase
X *
X * returns a pointer to IPCBasePort, creating, initializing and
X * adding it to the Exec public port list if it doesn't already exist.
X * This procedure will normally only be called by other IPC system
X * procedures (except possibly in a program such as a "broker").
X */
X
Xstruct IPCBasePort * OpenIPCBase()
X{
X char * pname = "IPC_Base_Port";
X struct MsgPort * port;
X
X if (IPCBasePort) return IPCBasePort;
X Forbid();
X if (!(IPCBasePort = (struct IPCBasePort *)FindPort(pname))) {
X IPCBasePort = (struct IPCBasePort *)
X AllocMem(SOL(struct IPCBasePort), MEMF_CLEAR | MEMF_PUBLIC);
X if (IPCBasePort) {
X port = & IPCBasePort->ipcb_Port.ipp_Port;
X port->mp_Node.ln_Name = IPCBasePort->ipcb_Port.ipp_Name;
X port->mp_Node.ln_Type = NT_MSGPORT;
X AddPort(port);
X NewList(&(IPCBasePort->ipcb_PortList));
X strcpy(IPCBasePort->ipcb_Port.ipp_Name, pname);
X }
X }
X Permit();
X return IPCBasePort;
X}
X
X/*** There is NO CloseIPCBase()!! (it stays around forever) ***/
X
X
X/*
X * CreateIPCPort is a private procedure which should not be called
X * directly by a user program. (Actually it is only called by GetIPCPort
X * but for clarity it is kept separate.)
X * The created IPCPort will be added to the list in IPCBasePort
X * (GetIPCPort won't allow duplicate names) unless the name is NULL,
X * in which case an "anonymous" port will be created that does not get
X * onto the list; such anonymous ports can only be accessed by other
X * processes if they are themselves passed as pointers in messages.
X * (Note that the call to this procedure MUST be within a
X * Forbid()/Permit() pair.)
X */
X
Xstatic struct IPCPort * CreateIPCPort(name) char *name;
X{
X struct IPCPort * port;
X int psize;
X
X if (!OpenIPCBase()) return NULL; /* Quick check before we do anything */
X psize = sizeof(struct IPCPort) + (name ? strlen(name) : 0);
X /* psize is actually one byte too big -- do you care? */
X port = (struct IPCPort *)
X AllocMem((LONG)psize, MEMF_CLEAR | MEMF_PUBLIC);
X
X if (port) {
X port->ipp_Size = (UWORD)psize;
X NewList(&(port->ipp_Port.mp_MsgList));
X port->ipp_Port.mp_Node.ln_Type = NT_MSGPORT;
X port->ipp_Port.mp_Flags = PA_IGNORE; /* initially */
X if (name) { /* anonymous port is not put on list */
X port->ipp_Port.mp_Node.ln_Name = port->ipp_Name;
X /* point to name storage array */
X strcpy(port->ipp_Name, name); /* move name to permanent storage */
X AddHead(&IPCBasePort->ipcb_PortList, port);
X }
X }
X return port;
X}
X
X
X/*
X * FindIPCPort
X *
X * Finds the IPCPort with the name supplied as argument if
X * it has been previously created.
X * Returns pointer to port if it exists AND has a server
X * -- null otherwise;
X * registers a new connection to the port (i.e. increments UseCount)
X * via UseIPCPort.
X * (Connection must be terminated when program is done by the procedure
X * DropIPCPort.)
X * It will notify a server if requested (see UseIPCPort).
X */
X
Xstruct IPCPort * FindIPCPort(name) char *name;
X{
X struct IPCPort * port;
X if (!OpenIPCBase()) return NULL; /* Quick check before we do anything */
X if (!name) return NULL; /* can't ever find an anonymous port! */
X Forbid();
X port = (struct IPCPort *)FindName(&IPCBasePort->ipcb_PortList, name);
X if (port) {
X if (port->ipp_Flags & (IPP_SERVED | IPP_LOADING))
X UseIPCPort(port);
X else
X port = NULL; /* no good if not currently served */
X }
X Permit();
X return port;
X}
X
X
X/*
X * GetIPCPort
X *
X * Returns a pointer to IPCPort with the name supplied as an argument;
X * unlike FindIPCPort, it always returns pointer to port -- this is
X * created if it doesn't exist; registers a new connection to the port
X * (use DropIPCPort when done). It will notify a server if requested
X * (see UseIPCPort).
X */
X
Xstruct IPCPort * GetIPCPort(name) char *name;
X{
X struct IPCPort * port=NULL;
X if (!OpenIPCBase()) return NULL; /* Quick check before we do anything */
X Forbid();
X if (name) /* port could be anonymous */
X port = (struct IPCPort *)FindName(&IPCBasePort->ipcb_PortList, name);
X if (!port)
X port = CreateIPCPort(name);
X if (port)
X UseIPCPort(port);
X Permit();
X return port;
X}
X
X
X/*
X * UseIPCPort
X *
X * Registers another connection to a port (outside this module,
X * this procedure is only used when the port was passed as a
X * pointer from another process).
X * (Use DropIPCPort when done.)
X * If the current server has set the IPP_NOTIFY flag in the port, the
X * server task will be signalled using the port signal bit. NOTE that
X * WaitPort will NOT detect these signals, because no message is
X * actually sent; the program must do a Wait on this bit, and should do
X * a GetMsg as usual, but if the message pointer is null it should
X * then call, for example, CheckIPCPort.
X * NOTE -- the port pointer MUST remain valid while this procedure is
X * called: either the call (from e.g. GetIPCPort) is Forbid()den, or
X * the port was passed from another process which guarantees its
X * existence.
X */
X
Xvoid UseIPCPort(port) struct IPCPort * port;
X{
X port->ipp_UseCount++;
X if (port->ipp_Flags & IPP_NOTIFY) /* Server wants to be notified */
X Signal(port->ipp_Port.mp_SigTask,
X 1L<<port->ipp_Port.mp_SigBit);
X}
X
X
X/*
X * DropIPCPort
X *
X * Terminate a connection to a port established by FindIPCPort,
X * GetIPCPort, or UseIPCPort. Port will be destroyed if there are
X * no other connections left.
X * If the IPP_NOTIFY flag is set in the port, the server will be
X * signalled when this procedure is called (see FindIPCPort).
X */
X
Xvoid DropIPCPort(port) struct IPCPort * port;
X{
X if (!port) return; /* to save the client some trouble
X (in a cleanup procedure) */
X Forbid();
X if (--port->ipp_UseCount == 0) {
X /* an anonymous port is NOT on list -- ALL others MUST be! */
X if (port->ipp_Port.mp_Node.ln_Name) Remove(port);
X Permit();
X FreeMem(port, (ULONG)port->ipp_Size);
X }
X else {
X if (port->ipp_Flags & IPP_NOTIFY) /* Server wants to be notified */
X Signal(port->ipp_Port.mp_SigTask,
X 1L<<port->ipp_Port.mp_SigBit);
X Permit();
X }
X}
X
X
X/*
X * ServeIPCPort
X *
X * Registers calling task as the server on the named port (which is
X * created if it doesn't exist); null is returned if the port already
X * has a server, otherwise a pointer to it is returned. At the same
X * time the port is given the server as its SigTask and a suitable
X * signal bit is allocated.
X */
X
Xstruct IPCPort * ServeIPCPort(name) char *name;
X{
X struct IPCPort * port;
X
X port = GetIPCPort(name);
X if (port) {
X Forbid();
X if ((port->ipp_Flags & (IPP_SERVED | IPP_SHUT))
X || (port->ipp_Port.mp_SigBit = AllocSignal(-1L)) == -1L) {
X DropIPCPort(port);
X port = NULL;
X }
X else {
X port->ipp_Port.mp_Flags = PA_SIGNAL;
X port->ipp_Port.mp_SigTask = FindTask(NULL);
X port->ipp_Flags = IPP_SERVED; /* all other bits cleared */
X }
X Permit();
X }
X return port;
X}
X
X/*
X * ShutIPCPort
X *
X * ONLY the current server may call this procedure.
X * It prevents more messages being sent to this port, but
X * does not end server connection; remaining messages can be dealt
X * with before finally calling LeaveIPCPort.
X * Note that it does NOT inhibit the server being signalled if
X * IPP_NOTIFY is set and another client connects. (At the moment
X * there is no mechanism to reopen a shut port without Leaving
X * first; this may be possible in a future revision.)
X */
X
Xvoid ShutIPCPort(port) struct IPCPort * port;
X{
X Forbid(); /* now required because of FindIPCPort test */
X port->ipp_Flags |= IPP_SHUT; /* Prevent other servers connecting */
X port->ipp_Flags &= ~IPP_SERVED; /* prevent messages from landing */
X port->ipp_Port.mp_Flags = PA_IGNORE; /* someone might use PutMsg! */
X Permit();
X}
X
X/*
X * LeaveIPCPort
X *
X * ONLY the current server may call this procedure.
X * Disconnects the server process from the port; another process
X * can then become a server if it desires. If there are no other
X * connections, the port is removed.
X */
X
Xvoid LeaveIPCPort(port) struct IPCPort * port;
X{
X FreeSignal(port->ipp_Port.mp_SigBit);
X port->ipp_Port.mp_SigTask = NULL;
X port->ipp_Flags &= ~(IPP_SHUT | IPP_SERVED | IPP_SERVER_FLAGS);
X DropIPCPort(port);
X}
X
X
X/*
X * CheckIPCPort
X *
X * Normally returns the number of current connections to this port
X * (including the server); if the top bit (0x8000) of the flags
X * argument is set, it will instead return the IPCPort flag word
X * value at the time of the call. (Note that these values are
X * not guaranteed!)
X * A call by the server (only) will also set the (user
X * settable) port flags to the value in the second argument --
X * currently the only valid flag is IPP_NOTIFY.
X */
X
XCheckIPCPort(port, flags)
X struct IPCPort *port;
X UWORD flags;
X{
X UWORD origflags = port->ipp_Flags;
X if (port->ipp_Port.mp_SigTask == FindTask(NULL))
X /* only server can change flags */
X port->ipp_Flags = (port->ipp_Flags & ~IPP_SERVER_FLAGS) |
X (flags & IPP_SERVER_FLAGS);
X return (int)((flags & 0x8000)? origflags : port->ipp_UseCount);
X}
X
X
X/*
X * PutIPCMsg
X *
X * Sends an IPCMessage to an IPCPort; if the port has no server or
X * is shut, the message is not sent and the function returns FALSE;
X * otherwise it returns TRUE. (Other port flags to be added later
X * may affect these actions.)
X * Note that a ReplyPort should be supplied in the message as usual
X * (except for the rare possible usage where a message is not to
X * be replied; in this case, the IPC_TRANSFER flag must be set in
X * both the message and all the items it contains, and the ReplyPort
X * must be NULL).
X */
X
XPutIPCMsg(port,msg)
X struct IPCPort *port;
X struct IPCMessage *msg;
X{
X Forbid(); /* we do this the straightforward way -- it's very quick */
X if (port->ipp_Flags & (IPP_SERVED | IPP_LOADING)) {
X PutMsg(port, msg);
X Permit();
X return TRUE;
X }
X Permit();
X return FALSE;
X}
X
X
X/*
X * CreateIPCMsg
X *
X * Creates a standard IPCMessage block (in MEMF_PUBLIC) with the
X * number of IPCItems supplied as argument. (Special cases -- like
X * in-line data -- you will have to handle yourself, and you always
X * have to manage the data blocks yourself).
X */
X
Xstruct IPCMessage * CreateIPCMsg(nitems, nxbytes, replyport)
X struct MsgPort *replyport;
X{
X ULONG msgsize, mlength;
X struct IPCMessage * mp;
X msgsize = sizeof(struct IPCMessage) +
X (nitems -1)*SOL(struct IPCItem) + nxbytes;
X mlength = msgsize - sizeof(struct Message);
X if (mlength > 0x0000FFFF)
X return NULL; /* no oversize messages! */
X mp = (struct IPCMessage *)
X AllocMem(msgsize, MEMF_CLEAR | MEMF_PUBLIC);
X if (mp) {
X mp->ipc_Msg.mn_Length = mlength;
X mp->ipc_ItemCount = nitems;
X mp->ipc_Msg.mn_ReplyPort = replyport;
X }
X return mp;
X}
X
X
X/*
X * DeleteIPCMsg
X *
X * Deletes a standard IPCMessage block; you must first have disposed
X * of any attached data as appropriate.
X */
X
Xvoid DeleteIPCMsg(msg) struct IPCMessage *msg;
X{
X FreeMem(msg, SOL(struct Message) + msg->ipc_Msg.mn_Length);
X}
X
X
X /*********************************************/
X
//END_OF_FILE
echo x - LoadIPCPort.c
sed 's/^X//' > LoadIPCPort.c << '//END_OF_FILE'
X/********************************************************************
X * *
X * LoadIPCPort module 88:7:22 *
X * *
X ********************************************************************/
X
X#include "IPCPorts.h"
X#include "IPC.h"
X
X#define IPPL MAKE_ID('I','P','P','L')
X#define PORT MAKE_ID('P','O','R','T')
X
Xextern struct IPCBasePort *IPCBasePort;
X
X/*
X * LoadIPCPort
X *
X * Gets an IPCPort of the specified name. If it is not already
X * being served or had a server being loaded, a message is sent
X * to IPCBasePort (if IT has a server) requesting that a server
X * be supplied.
X * If, when the message is replied, the port is flagged as served
X * or being loaded, the port pointer is returned. If no server is
X * available, it drops the port again and returns NULL.
X */
X
Xstruct IPCPort * LoadIPCPort(name) char *name;
X{
X struct IPCPort *port=NULL,
X *RPort = NULL;
X struct IPCMessage *mesg = NULL;
X struct IPCItem *item;
X
X port = GetIPCPort(name);
X if (!port) return NULL;
X if (port->ipp_Flags & (IPP_SERVED | IPP_LOADING))
X return port;
X if ((RPort = ServeIPCPort(NULL)) /* only a replyport really */
X && (mesg = CreateIPCMsg(1L, 0L, (struct MsgPort *)RPort))) {
X mesg->ipc_Id = IPPL;
X item = mesg->ipc_Items;
X item->ii_Id = PORT;
X item->ii_Ptr = (void *)port;
X if (PutIPCMsg((struct IPCPort *)IPCBasePort, mesg)) {
X WaitPort(RPort);
X GetMsg(RPort);
X }
X }
X if (RPort) LeaveIPCPort(RPort);
X if (mesg) DeleteIPCMsg(mesg);
X if (port->ipp_Flags & (IPP_SERVED | IPP_LOADING))
X return port;
X DropIPCPort(port);
X return NULL;
X}
X
X
//END_OF_FILE
echo x - Broker.c
sed 's/^X//' > Broker.c << '//END_OF_FILE'
X/* Primitive test program for LoadIPCPort facility */
X/* ...simply displays a request for a port in its console window */
X
X#include "IPCPorts.h"
X#include "IPC.h"
X
X#include "exec/memory.h"
X#include "exec/tasks.h"
X#include "libraries/DOS.h"
X
X#define SOL(s) ((LONG)sizeof(s))
X
X#define IPPL MAKE_ID('I','P','P','L')
X#define PORT MAKE_ID('P','O','R','T')
X
X
Xstruct IPCPort *brokerport; /* actually IPCBasePort -- for convenience */
Xstruct IPCMessage *imsg=NULL;
X
Xvoid baditem(struct IPCItem *, ULONG);
Xvoid outputstr(char *);
X
Xstruct Task * FindTask(char *);
X
Xstruct IPCPort * ServeIPCBase();
Xvoid ShutIPCBase();
Xvoid LeaveIPCBase();
Xvoid Cleanup();
X
X
XULONG bportsig = 0; /* signal masks for port */
X
Xint active = TRUE;
X
X
Xvoid _main()
X{
X ULONG sigset;
X
X brokerport = ServeIPCBase();
X if (!brokerport) _exit(11);
X bportsig = 1<<brokerport->ipp_Port.mp_SigBit;
X
X
X do {
X while ( procimsg() ) ; /* loop */
X if (active) {
X sigset = Wait(bportsig | SIGBREAKF_CTRL_C);
X if (sigset & SIGBREAKF_CTRL_C) {
X active = FALSE;
X ShutIPCBase(); /* not really necessary... */
X continue; /* so we clear out any messages that sneak in */
X }
X }
X } while (active);
X outputstr("Broker terminating...\n");
X
X Cleanup();
X}
X
X
Xvoid Cleanup()
X{
X LeaveIPCBase();
X}
X
X
Xprocimsg()
X{
X struct IPCItem *item;
X if (!(imsg = (struct IPCMessage *) GetMsg(brokerport))) return FALSE;
X item = imsg->ipc_Items;
X if (imsg->ipc_Id == IPPL && item->ii_Id == PORT
X && loadport(item->ii_Ptr)) /* everything OK */;
X else imsg->ipc_Flags |= IPC_NOTKNOWN;
X ReplyMsg(imsg);
X return TRUE;
X}
X
X
Xvoid baditem(item, extraflags)
X struct IPCItem *item;
X ULONG extraflags;
X{
X imsg->ipc_Flags |= IPC_CHECKITEM;
X item->ii_Flags |= IPC_NOTKNOWN | extraflags;
X}
X
Xvoid outputstr(str) char *str;
X{
X Write(Output(), str, strlen(str));
X}
X
X
X/*
X * loadport(portptr)
X *
X * -- actually initiates the loading procedure (here just a skeleton).
X * returns TRUE if successful, otherwise FALSE.
X */
X
Xloadport(port) struct IPCPort *port;
X{
X outputstr("Please load server for port '");
X outputstr(port->ipp_Name);
X outputstr("' -- Thanks\n");
X port->ipp_Flags |= IPP_LOADING;
X return TRUE; /* -- doesn't know how to fail yet... */
X}
X
X
X/****************************************************************/
X
X/*
X * The following procedures are simple conversions (the first is
X * a direct copy) of the corresponding ones in IPC.c.
X * The standard IPC module itself is not needed.
X */
X
Xstruct IPCBasePort *IPCBasePort = NULL;
X
X
Xstruct IPCBasePort * OpenIPCBase()
X{
X char * pname = "IPC_Base_Port";
X struct MsgPort * port;
X
X if (IPCBasePort) return IPCBasePort;
X Forbid();
X if (!(IPCBasePort = (struct IPCBasePort *)FindPort(pname))) {
X IPCBasePort = (struct IPCBasePort *)
X AllocMem(SOL(struct IPCBasePort), MEMF_CLEAR | MEMF_PUBLIC);
X if (IPCBasePort) {
X port = & IPCBasePort->ipcb_Port.ipp_Port;
X port->mp_Node.ln_Name = IPCBasePort->ipcb_Port.ipp_Name;
X port->mp_Node.ln_Type = NT_MSGPORT;
X AddPort(port);
X NewList(&(IPCBasePort->ipcb_PortList));
X strcpy(IPCBasePort->ipcb_Port.ipp_Name, pname);
X }
X }
X Permit();
X return IPCBasePort;
X}
X
X
X
Xstruct IPCPort * ServeIPCBase()
X{
X struct IPCPort * port;
X
X port = (struct IPCPort *)OpenIPCBase();
X if (port) {
X Forbid();
X if ((port->ipp_Flags & (IPP_SERVED))
X || (port->ipp_Port.mp_SigBit = AllocSignal(-1L)) == -1L) {
X port = NULL;
X }
X else {
X port->ipp_Port.mp_Flags = PA_SIGNAL;
X port->ipp_Port.mp_SigTask = FindTask(NULL);
X port->ipp_Flags = IPP_SERVED; /* all other bits cleared */
X }
X Permit();
X }
X return port;
X}
X
Xvoid ShutIPCBase()
X{
X struct IPCPort *port;
X if (!IPCBasePort) return;
X port = &IPCBasePort->ipcb_Port;
X port->ipp_Flags |= IPP_SHUT; /* Prevent other servers connecting */
X port->ipp_Flags &= ~IPP_SERVED; /* prevent messages from landing */
X port->ipp_Port.mp_Flags = PA_IGNORE; /* someone might use PutMsg! */
X}
X
X
Xvoid LeaveIPCBase()
X{
X struct IPCPort *port;
X if (!IPCBasePort) return;
X port = &IPCBasePort->ipcb_Port;
X FreeSignal(port->ipp_Port.mp_SigBit);
X port->ipp_Port.mp_SigTask = NULL;
X port->ipp_Flags = 0;
X}
X
X
//END_OF_FILE
echo x - Broker.lnk
sed 's/^X//' > Broker.lnk << '//END_OF_FILE'
XFROM LIB:c.o,Broker.o
XTO Broker
XLIBRARY LIB:lc.lib,LIB:amiga.lib
XMAP Broker.map,f,h,,s,x
X
X
X
//END_OF_FILE
echo "End of archive."
# end of archive.
exit 0