the commkit software operating system hides the idiosyncracies of the hardware by offering a...

26
The Commkit Software Operating System hides the idiosyncracies of the hardware by offering a common, wel l-defined interface to the user. Many OS also support pseudo-concurrent ex ecution of a number of tasks, referred to as processes. Processes may need to communicate inte rprocess communication or IPC. Message passing is one of the IPC mechani sms. Commkit is a small, event driven monitor that support multiple processes and messa ge passing in MS-DOS.

Post on 22-Dec-2015

213 views

Category:

Documents


0 download

TRANSCRIPT

The Commkit Software Operating System hides the idiosyncracies of the hardware b

y offering a common, well-defined interface to the user.

Many OS also support pseudo-concurrent execution of a number of tasks, referred to as processes.

Processes may need to communicate interprocess communication or IPC.

Message passing is one of the IPC mechanisms.

Commkit is a small, event driven monitor that support multiple processes and message passing in MS-DOS.

Overview of Commkit

The structure of a Commkit Program

Foreground Process Background Processes (Optional) Network Emulators (Optional) Commkit (Interrupt Handler and Message Software) Hardware

A Commkit executable program is made by linking one or more modules containing a foreground process with the Commkit interrupt handlers and message-handling software.

Background processes and network emulators are optional.

All entities (i.e., foreground and background processes, network emulators) communicate via message using send( ) and recv( ).

Each entity is associated with a unique process identifier, a message queue, and entry point known to Commkit, and a series of procedures implementing the process.

Every Commkit executable program requires a mainline procedure, called main( ), which is the entry point from MS- DOS.

Commkit is initialized in the mainline with a call to initialize( ) that sets up the message queues, interrupt handlers, and various support routines.

Main Programvoid main(){ /* - mainline for ipc - execution begins after user types `ipc' after DOS prompt */

initialize(); /* initialize Commkit */

register_background(BACKGROUND_1, clock_signal);

register_background(BACKGROUND_2, screen_display);

clear_scr(0, 79, 0, 24);

do_ipc(); /* foreground process */

rtn_to_dos();

}

The Foreground Process The foreground process is simply an algorithm implemented as a C function that is called by the mainline. The basic structure of the foreground process is a large loop that is terminated when some condition is reached. (e.g., CTRL-C is typed). void foreground_process ( ) { int running = TRUE; while (running) { recv( ); /* some condition is reached * / running = FALSE; } }

The foreground process is interruptable by any interrupt handlers.

Control remains with the foreground process until it attempts to receive a message.

If a message is available, it is returned immediately to the foreground process;

Otherwise, the process is blocked and any background processes with pending messages are allowed to execute.

As soon as a message arrives for the foreground process, control (and the message) are returned to it.

The foreground process is associated with the process identifier APPLICATION.

There is only ONE foreground process.

Do_ipcvoid do_ipc(){int done = FALSE; /* TRUE when ETX detected */int src; /* Source of the character */char ch; / * Character from user */ do {

if (recv(&src, APPLICATION, &ch, 1) == 1) /* waits for messages from the keyboard (KEYIH) sent to queue APPLICATION */

{ if (src == KEYIH) { if (ch == ETX) /*execution is terminated when */

done = TRUE; /*the user enters control C (ETX). */

elsesend(APPLICATION, BACKGROUND_2, &ch, 1);

/* keyboard characters are sent directly to process BACKGROUND_2 for displaying */

} else message(1, 20, INVERSE, "Unknown src");

} } while (!done);}

Background Processes There can be zero or more background processes.

Background processes are executed only when the foreground process is idled (i.e., waiting for a message) and a message is available for the background process.

Background processes should not contain software that waits for multiple messages or implements infinite loops.

The entry point (i.e., a procedure) associated with a background process must be declared as type void.

Each background process is identified with a unique identifier, e.g., BACKGROUND_1, BACKGROUND_2, etc.

Clock_signalvoid clock_signal(){char signal; /* Data from clock (ignored) */int src; /* Source of the message (ignored) */ if (recv(&src, BACKGROUND_1, &signal, 1) == 1) /*called once a second */ /* receives messages from the BACKGROUND_1 queue */ { seconds++; if (seconds > 59) { seconds = 0;

minutes++; update_tod(minutes, tod . mm); /*update the tod (time-of-day) structure*/ } if (minutes > 59) { minutes = 0;

update_tod(minutes, tod . mm); hours++; update_tod(hours, tod . hh);

} update_tod(seconds, tod . ss); send(BACKGROUND_1, BACKGROUND_2, (char*) &tod, sizeof(tod)); } /*sent to BACKGROUND_2 for displaying */}

Interrupt Handlers

Commkit supports five external devices, each of which is associated with an interrupt handler.

An interrupt handler is associated with a process identifier. Identifier Interrupt Handler KEYIH Keyboard CLKIH Clock SP1IH Serial port 1 SP2IH Serial port 2 PPIH Parallel port

The void interrupt type in Turbo C can be associated with either a variable or a C function. A variable of this type can hold the 32-bit address (segment and offset) of an interrupt handler. A void interrupt function causes the compiler to generate the necessary instructions to save all registers on the stack upon entry to the function. Upon exit from the function, the compiler generates the code to restore the registers (by popping them from the stack). Setvect( ) stores the address of an interrupt handler in the specified interrupt vector. setvect (KEY_INT, kb_ih); Getvect( ) returns a copy of the 32-bit interrupt address stored in a specific interrupt vector. old_clock = getvect (CLK_INT);

Interrupt Handler - Process Communication

Since different applications of Commkit may require that messages generated by the interrupt handlers be sent to different processes, the application software is expected to determine the destination of any interrupt-handler data.

Accordingly, all interrupt handlers call the external function low_level( ) upon completion of their interrupt to allow the application to decide on the final destination of, e.g., a character read from the keyboard.

void low_level (int device, int code, unsigned char data)

where device is the process identifier of the device associated with t

he call to low_level( ). (KEYIH, CLKIH,…); code is the cause of the call to low_level, one of 0 : The field is to be ignored RECV DONE : A data available interrupt has occurred. XMIT DONE : The transmit holding register is empty. MODEMSTATUS: A modem has been received from a process for the interrupt handler specified in device. data is the data, if any, associated with the call to low_level( )

Low_levelvoid low_level(int device, int code, unsigned char data){ /* responsible for routing messages from the different interrupt handlers to specific processes. */ static int sec_count = 0; /* Count of number of clock ticks in a second */ switch(device) { case SP1IH: case SP2IH:

message(0, 40, INVERSE, "SPxIH called!"); break; case CLKIH: /*clock messages to BACKGROUND_1 */

if (sec_count++ > HZ){ sec_count = 0; low_level_send(CLKIH, BACKGROUND_1, &data, 1);}break;

case KEYIH: /*keyboard characters to APPLICATION */low_level_send(KEYIH, APPLICATION, &data, 1); break;

case PPIH: break; default: message(0, 40, INVERSE, "Bad device call"); break; }}

The keyboard Interrupt Handler

The keyboard interrupt handler software consists of three procedures : -- keyboard_init( ). The keyboard initialization software. -- kb_ih( ) The keyboard interrupt entry point, called whenever a keyboard interrupt occurs. kb_ih( ) passes control to keyboard_handler( ). -- keyboard-handler. The keyboard-interrupt processing software, called from kb_ih( ), converts the scan code into the equivalent ASCII character and store it in the variable ascii. Once the character has been generated, the keyboard_handler( ) calls low_level( ) with the character ascii for forwarding to the appropriate process.

The Clock Interrupt Handler The commkit clock interrupt handler uses the 8253 timer chi

p to supply timing signals to applications. When a clock interrupt occurs, control is first passed to clk

_ih( ) and then to clock_handler( ). Clock_handler( ) then calls low_level( ) with an indication that a clock interrupt has occurred. Once the clock interrupt has been processed, control is not passed back to the previously executing process. Instead, the stack is modified to appear as if an interrupt has just occurred, and the original MS-DOS clock interrupt handler is than called. – chaining. Once the MS-DOS clock interrupt handler has finished, the control is returned to clk_ih( ).

Message Handling Commkit permits any entity to communication with any other entity by sending messages.

All processes are message-driven; that is, a process is idle until it is sent a message.

Since an entity may be sent a message while it is processing an earlier message, all pending messages are queued until they can be received by the entity.

entity 1

entity 2

entity 3

A message is any data structure having a maximum size of 128 bytes.

Message is kept in the structure queue_entry.

All queue entries associated with an entity are linked together through the field next.

Commkit maintains a table queue, in which each entry corresponds to the list of messages waiting to be received by an entity.

*next source size msg.

3 5

9 10 Hello Evan

1 2 0000

head

tail

queue

Entity number

1

The Send Primitive

Allows an entity to send a message to another entity. int send (int scr, int dst, char *msg, int size)

The Receive Primitive Allows an entity to receive a message sent from another entity int recv (int *src, int dst, char *msg, int size)

where: *scr is the identifier of the entity that has sent the message; returned by the received primitive software.

Implementation of the Message-Handling Software

The send( ) function is an enqueuing operation. It is possible for an interrupt to occur at the same time a high- level process is sending a message. Should the interrupt handler also send a message, the queue data structures may be damaged, resulting in inconsistencies. Sections of code that access shared data (such as message queue) are known as critical regions and must be protected against “concurrent” access. In Commkit, the queue is a critical region, and it is protected from concurrent access by the disabling of interrupts.

The send( ) function does not disable interrupt explicitly. It place all the parameters (src, dst, *msg, size) in a structure msg-struct. The address of msg-struct is passed to commkit using the ds register and causing a software interrupt via interrupt vector 50. An interrupt handler, send_ih( ), is associated with interrupt vector 50. A call takes place to low_level_send( ), which enqueues the supplied message.

High-level application( )

send( )

Commkit send_ih( )

low_level_send( )

Recv( ) Implementation

Recv( ) primitive is also implemented via software interrupt (vector 51). When the foreground process executes recv( ). -- if a message is available, the message is returned. -- if no message available, foreground process is suspended and control passes from recv( ) to do_other_tasks( ). The background process is called from do_other_tasks( ). Do_other_tasks( ) obtains the process identifier and the entry point from the array back_list. When a message becomes available for the foreground process, control returns to recv( ).

Support Routines Display a single character on the screen at a specific line and column

Display a string with certain attributes staring at a specific line and column

Convert a 16-bit integer to a 5-byte string

Move the cursor to a specific location

Clear portion of the screen

void display(int line, int column, char character, char attributes)

void message(int line, int column, int attributes, char *string)

void int2hex(int number, char *string)

void move_cursor(int newx, int newy)

void clear_scr(int xup, int xlo, int yup, int ylo)

IPC Example Using Commkit Write a program that will allow a user to enter data from a PC’s keyboard and display it on the PC’s screen.Simultaneously, the time elapsed since the program started execution should be displayed as “hh:mm:ss” in the upper left corner of the screen. When the user attempts to type beyond the last line of the screen, the screen should be cleared and the cycle should be continued.A Ctrl-C entered by the user should terminate the program, returning to MS-DOS.

Design Considerations The problem is divided into three separate tasks:

1. P1: accepts characters from keyboard_handler(), scans for Ctrl-C, and forwards all other characters to P3.2. P2: accepts timing signals from clock_handler(), converts them into a data structure consisting of hours, minutes, and seconds. The data structure is then forwarded to P3.3. P3:displays individual characters (from P1) or character strings (from P2).

P1

keyboard_handler() clock_handler()

P3 P2

Implementation ipc.c

1. P1, APPLICATION: do_ipc()

2. P2, BACKGROUND_1: clock_signal()

3. P3, BACKGROUND_2: display_screen()

P1

keyboard_handler() clock_handler()

P3 P2