[alt.sources.amiga] ipc.src -- Source for P/P IPC

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