Programming AmigaOS in C

24. Message Ports

A message port is basically a system to allow data to be passed between programs. Messages are collected at a port, and organised as a list wuith new messages appended at the end of the list. A pre-defined arrival action may also be invoked. This action might do nothing, call a task signal or a software interrupt.

Message Port has the following structure, defined in exec/ports.h.

struct MsgPort {
	struct Node mp_Node;     /* This is a standard Node structure which is used by tasks to use a message port by name. */
	UBYTE mp_Flags;          /* this is to specify a message arrival action which can be PA_SIGNAM for signal numbers, PA_SOFTINT for a software interrupt or PA_IGNORE to perform no operation. */
	UBYTE mp_SigBit;         /* Contains the signal bit number if mp_Flag is set to PA_SIGNAL */
	void *mp_SigTask;        /* Contains a pointer to the task to be signaled. If it is a software interrupt, then it points to an Interrupt structure */
	struct List mp_MsgList;  /* Contains a list of Messages that is queued on this Message port */
}

The Message Port can be initialised by exec's CreateMsgPort function. No parameters are required. Set any values afterwards such as:
myMsgPort->mp_Node.ln_Name = "Name of port";
myMsgPort->mp_Node.ln_Pri = 0; /* priority */

Alternively, the Message Port can be created using the amiga.lib CreatePort() function . Two parameters are required:
name = The name of the port, in most cases ports should not be named except when ports are used for rendez-vous between tasks.
pri = The priority of the public port list, normally this is 0.

Example,

struct MsgPort *myMsgPort;

myMsgPort = CreateMsgPort();
or
myMsgPort = CreatePort("myport", 0);

To remove a message port use the Deleteport or DeleteMsgPort function with the name of the MsgPort structure.

if (myMsgPort) DeletePort(myMsgPort);
or
if (myMsgPort) DeleteMsgPort(myMsgPort);

To make a Message Port public, use the AddPort function. These ports can be located using the FindPort function.

AddPort(myMsgPort);

Once finished with a public Message Port, use the RemPort function to remove it from the list.

if (myMsgPort) RemPort(myMsgPort);

If the MsgPort is going to cause a software interrupt, then you need to create an Interrupt structure.

struct Interrupt {
	struct Node is_Node;		/* The node type should be set to NT_INTERRUPT or NT_UNKNOWN */
APTR is_Data; /* Data segment pointer */
VOID (*is_Code)(); /* Pointer to function for interrupt */ }



The function Cause() is called with the interrupt structure to perform the interrupt.

Cause(myInterrupt);

Once a message port is created and opened, you can send messages through these ports, these use the Message struct,

struct Message {
   struct Node mn_Node;	/* A standard node structure for port linkage */
	struct MsgPort *mn_ReplyPort; /* A port used by the ReplyMsg function */
	UWORD mn_length;	    /* The length of the message including user-defined */
}

The message structure above becomes part of another user defined message structure which includes whatever data values you want to pass to other tasks, you can have one or more values in your structure. For example, the XYMessage structure contains the above Message structure, which it requires, and X, Y values to be passed on through the port.

struct XYMessage {
	struct Message xy_Msg;  /* This should always be included as part of your message */
	UWORD xy_X;             /* X and Y user defined values, you can add other entries if you wish. */
	UWORD xy_Y;
}


To actually send a message, you use the PutMsg function, where you specify the Message Port and the message, containing the data, to send to another task.

PutMsg( msgPort, userStructure);

The FindPort function allows the system to locate a message port on the system to communicate with it, specify a port name to locate.

msgPort = FindPort ("port_name");

A special note, you must run a call to Forbid() function to prevent other tasks from running while sending the message, then run Permit() function afterwards.

/* xyport.c */
struct
MsgPort *xyport, xyreplyport, port; struct XYMessage *xymsg, *msg; BOOL foundport;
if (xymsg = (struct XYMessage *)AllocMem(sizeof(struct XYMessage), MEMF_PUBLIC | MEMFCLEAR)) 
{
	if (xyreplyport = CreateMsgPort()) {
		xymsg->xy_Msg.mn_Node.ln_Type = NT_MESSAGE;		/* It is message node type - see exec/nodes.h */
		xymsg->xy_Msg.mn_Length = sizeof(struct XYMessage); /* The size of the XYMessage structure */
		xymsg->xy_Msg.mn_ReplyPort = xyreplyport;		/* Which port to reply to - see ReplyMsg function */
		xymsg->xy_X = 10;								/* The actual values to send in this message */
		xymsg->xy_Y = 20;

		Forbid();
		port = FindPort("xyport");  /* Specify this task's port name - usually the name of program to make it unique. */
if (port) PutMsg(port, xymsg); /* Send the message to the port */
Permit(); foundport = (ULONG)port; /* Check to see port still exists */ if (foundport) { /* Wait for someone to respond - you can use the WaitPort or Wait functions, then process the data. */ } DeleteMsgPort(xyreplyport); /* remember to remove any reply ports */ } FreeMem(xymsg, sizeof(struct XYMessage)); /* clean up memory allocations */ }

Once a port has been sent to the system , the other task will need to able to read the message from the Message Port. You can use the WaitPort function to wait for a message to appear and save the data in a new data structure to be processed by the task. The GetMsg function also can be used to get the next mssage from a message port, unlikeWaitPort it does not wait for a message to be available, if no message was received then zero is returned.
Once you have retrieved a message, you then should use the ReplyMsg function to remove it from the system and say that you have done with it.

message = WaitPort(myport);

message = GetMsg(myPort);

ReplyMsg(message);

Example,

struct Message xyMsg;
struct MsgPort xyReplyPort;
UWORD x,y;
while (xymsg = WaitPort(xyReplyPort)) /* Retrieve next available message */

{
	x = xymsg->xy_X;	/* Retreive x,y values from message */
	y = xymsg->xy_Y;
printf("x=%ld y=%ld\n", x,y); /* Display x,y values */
ReplyMsg(xyMsg); /* Finished with message */
}



You now have the features needed to transmit data between tasks and process them.

Internet and BSD sockets