Events (Signals)
Events are primarily used by the kernel to communicate with programs. They can be related to Unix signals. Examples of events can be:
- a key was pressed
- a message was received
- the mouse was moved
- the mouse was clicked
- an interrupt was triggered (in a driver)
An event is represented by this structure:
Code: Select all
typedef struct
{
unsigned int Type;
unsigned int Action;
unsigned int Data1;
unsigned int Data2;
unsigned int Data3;
} EVENT;
There are two system calls related to events, one places the current thread into a sleep if there are no pending events, and the other gets the first pending event. Most event-based programs use these system calls together so that a program spends most of its time sleeping when there are no events to handle. Real time programs (for example, a game) omit the first system call so that they are constantly running. If the second system call is called when no events are pending, then the kernel returns an event where Type equals NOTHING (or 0).
I have reserved a special event type (USER-DEFINED) which I was going to use for fast interprocess communication (program specific user-defined events?), but I have decided against this idea, since some programs may abuse this system and send KEYBOARD/KEYDOWN events to random programs.
Messages
A message is a block of data of varying size that can be sent between processes.
A message is sent simply by finding the Process ID of the recipient, and telling the kernel where the message is in memory, and how big it is. The kernel automatically generates a Message ID, which the sending process need not to worry about.
To receive a message, the receiving program must allocate its own memory to store the message, and tell the kernel the Message ID of the message it wants to receive and where in memory to store it. If the Message ID does not match any pending messages, no error messages are generated, and the memory is left unchanged. If the program can't allocate enough room or doesn't want to accept a message (e.g. it only wanted messages from a specific program) then it can ask the kernel the scrap a message.
There are two ways of finding out the Message ID, the size of the message, and the Process ID of the sending message. The first way; when a message is sent an event will be sent to the receiving process that says this information. The second way; the receiving program can make a system call which returns this information and also states how many messages there are waiting on the queue.
This system is great and efficient for small messages, but may create some overhead for larger messages (more than a few megabytes).
Pipes
A pipe is the same as a Unix pipe (first-in-first-out stream of raw bytes), except they are represented by a number instead of a name. This number is specific to each program.
There are three modes a pipe can run in (from the individual program's point of view):
- Send: The program can send data on this pipe but not read from it.
- Receive: The program can receive data on this pipe but not send from it.
- Pool: The program can send and receive from the pipe. It's not really a two way pipe, but rather a pool of data each process can add to and read from.
There are system calls to write to a pipe, read from a pipe, and to find out how much data is in the pipe.
A program may create a pipe and write to it straight away without the other program acknowledging that this pipe exists. The other program will know a pipe exists because they will receive an event telling them a pipe was created along with the process ID of the program on the other side of the pipe and the mode the pipe is operating in (SEND, RECEIVE, POOL). The program will also receive an event if a pipe is closed.
If either program closes, then the pipe will close and all data within the pipe will be lost.
Shared memory
Probably the system I've given the least thought to, and the most insecure form of IPC. It'll mostly be used by drivers that need to transfer large amounts of memory from one address to another.
For sharing memory between programs, I might have some sort of acknowledgment system, or leave it out all together. Nothing has been finalised for now.
For sharing memory between drivers (programs marked as 'drivers' - drivers run in user-space in my micro kernel environment), they can map/unmap any part of physical memory and the kernel will automatically find somewhere in the driver's addressing space to allocate it.
Tell me what you all think. I'm welcome to any suggestions.