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