NAT L INST. OF STAND & TECH R.I.C.

A111D4 ObEbL.4

NATIONAL INSTITUTE OF STANDARDS &

TECHNOLOGY

Research Information Center

Gaithersburg, MD 20899

, PUBLICATIONS

COMMON MEMORY

FOR THE PERSONAL COMPUTER

A11102 6=1017

RESEARCH

SERIES

NISTIR 88-3838

By:

Siegfried Rybczynski

August 11

;g?.g^^xbToP4flg%%§wbr<J p.i : o: o?.p qq:oxcP.p{

. .:co:q:o9.£?a?sstao:q:<i

T<bY6:bx*P/&&b:Y^

Td?.;P.L: S:c§o:b:^

•Lpb!gSg+°^!oxi>TpR;S

lilpli si

JKcibPiPyi^oicixt iPgpghgS^SorbP.- s-SpMptp.?!-????

;Ki>:o:oMt>!pO;Hxo:o.oP.o!<:H^;yp;o:<b5o:

IS«I«*1J*

§fe1o%^<^

i5H§|p§^
. ' 1
RESEARCH INFORMATION CENTER

Nat i onal Institute of

Standards and Technology

Gaithersburg, MD 2089?

Common Memory for the Personal Computer

Siegfried Rybczynski

August 11, 1988

DISCLAIMER

Certain commercial equipment, instruments, or materials are

identified in this document in order to adequately specify the

experimental procedure. Such identification does not imply

recommendation or endorsement, nor does it imply that the

materials or equipment identified are necessarily the best

available for the purpose.

Common Memory for the PC

Table of Contents

I. Introduction

1. Organization of this Document

2 . History of Common Memory

3. Purpose of this Software Collection

4. Computer Configuration Requirements

II . Overview of the Common Memory Architecture

1 . Common Memory Components

1.1. Mailboxes and Mailgrams

1.1.1. Mailgram Format

1.1.2. Mailbox and Mailgram Properties

1.2. Common Memory Manager

1.2.1. Active Common Memory Manager

1.2.2. Passive Common Memory Manager

2. Coordinating Mailbox Access

2.1. Read While Write is Active

2.2. Update Frequency Exceeds Read Frequency

2.3. Read Frequency Exceeds Update Frequency

2.4. Multiple Readers of a Common Mailbox

2.5. Multiple Writers to a Common Mailbox

3 . Mailbox Management

3.1. Declare Access Requirements for Each Mailbox

3.2. Perform the Read or Write Action

3.3. Undeclare Mailbox Access

4 . Mailbox Access Methods

4.1. Explicit Mailbox Access

4.2. Implicit Mailbox Access

4.3. Conversion of Implicit to Explicit Systems and

Explicit to Implicit Systems

5 . Existing Common Memory Implementations

5.1. Common Memory Maps into the Process's Address

Space

5.2. Common Memory as a Separate Process

5.3. The Global Common Memory

6 . Summary

6.1. Common Memory - An Application Interface

6.1.1. Benefits of Common Memory

6.1.2. Drawbacks to Common Memory

6.2. Alternatives to Common Memory

i
Common Memory for the PC

III

IV.

PC Common Memory Architecture Description

1. Mailboxes And Mailgrams

1.1. Coordinating Common Memory Access

1.1.1. Read While Write is Active

1.1.2. Update Frequency Exceeds Read Frequency

1.1.3. Read Frequency Exceeds Update Frequency

1.1.4. Multiple Readers of a Common Mailbox

1.1.5. Multiple Writers to a Common Mailbox

1.2.

Mailgram Format

2 . Common Memory Access Method

3 . Mailbox Management

3.1. Declare Access Requirements for Each Mailbox

3.2. Perform the Read or Write Action

3.3. Undeclare Mailbox Access

3.4. Mailbox Management Extensions

3.4.1. Disconnect the Application From Common Memory

3.4.2. Check for Mail

Programmer Reference

1 . Implementation Issues

1.1. The Compiler

1.2. Memory Allocation and Usage

1.3. Interfaces to Languages Other Than C

1.4. Non-portable Common Memory Functions

2. The Common Memory Interface Library

2.1. Introduction to Common Memory Manipulations

2.2. Functions That Provide Common Memory Access

2.2.1. Function cm_d@clare

2.2.2. Function cm__und@clare

2.2.3. Function cm_writ@

2.2.4. Function cm__read

2.2.5. Function cm_ckmail

2.2.6. Function cm disc

2.3.

Functions That Provide Information About Common

Memory Usage

2.3.1. Function cm_get__fsm_list

2.3.2. Function cm_get_mbx__list

2.3.3. Function cm_get_cm_stats

2.3.4. Function cm_get_fsm_stats

2.3.5. Function cm_get_mbx_stats

3

Convenience Functions

3.1. Function cm_free_update_list

3.2. Function crn_get__statusname

3.3. Function cm ini

%

ii
Common Memory for the PC

4. Global Common Memory Variables

4.1. CM_DEBUG_LEVEL - Control the Amount of Common

Memory Debugging Information Displayed

4.2. CM_GET_STATS - Control the Acquisition of Common

Memory Statistics

4.3. CM__VERS I ON - Determine Version Numbers of the

Common Memory Distribution Components

5. Application Program Development

5.1. The PC Common Memory Distribution Kit

5.2. Compiling Programs That Use the Common Memory

Library

5.3. Linking Programs That Use the Common Memory

Library

Appendix A. Status Report Codes For The Common Memory Interface

Functions

Appendix B. Common Memory Mailbox Access Codes

Appendix C. Data Structures Used in the Common Memory Interface

Functions

C.l. Standardized Definitions

C.2. Update List Structure

C.3. Common Memory Statistics

C.3.1. Function Call Statistics

C.3.2. Mailbox and Client Lists

C. 3.3. Mailbox and Client Statistics

Appendix D. Sample Program Demonstrating a Common Memory Mailbox

Interaction Between Two Logically Separate

Applications

Dd. Purpose of the Program

D. 2. Program Listing

D. 3. Sample Program Output

Appendix E. Source Code Listings of the Common Memory Programs

E. l. CM_CONST.H

E.2. CM_GLOBALS.H

E.3. CMJTYPES.H

E . 4CM_FUNCS .

E.5. CM__UTILS . C

E.6. SFUNCS.C

Glossary

List Of References

iii
Common Memory for the PC

List Of Figures

Figure Description Page

1-1 Local Common Memory 1-3

1-2 Global Common Memory 1-4

11-1 Generic Mailbox Structure II-2

11-2 Special Mailbox Structure Used When

A Common Memory Manager Is Absent

II-3

11-3 General Mailgram Format Used In A

Mixed Common Memory Environment

11-4

111-1 Generic PC Mailbox Structure I II” 3

111-2 Underlying PC Mailgram Format III-4

iv
Common Memory for the PC

I. INTRODUCTION

1. ORGANIZATION OF THIS DOCUMENT

Section I serves as an introduction to the concept of common

memory. It identifies the purpose of the accompanying software

collection, and lists the personal computer (PC) configuration

prerequisites of the PC common memory software library.

Section II provides an overview of the common memory architecture

defined by the Automated Manufacturing Research Facility ( AMRF

)

of the National Bureau 'of Standards. A short personal opinion of

the drawbacks to common memory is provided at the end of the

section.

Section III specifies the PC common memory architecture. The

AMRF architecture allows for a range of solutions to meet

specific management and access coordination problems. This

section identifies which solutions (or alternatives) were

implemented in the PC common memory architecture. Some minor

extensions to the original architecture are presented.

Section IV is the programmer's reference section. It lists all

PC common memory function calls and details their argument lists

and return values. A functional description of each function is

provided

The various appendices provide detailed support information for

the use of the PC common memory program library. Included are

data structure definitions, a sample program and associated

output, and the complete source listing of the PC common memory

library.

I - 1
Common Memory for the PC

2. HISTORY OF COMMON MEMORY

The Automated Manufacturing Research Facility ( AMRF ) at the

National Bureau of Standards (NBS ) is using an architecture

called "common memory" for interprocess communication.

The AMRF common memory architecture originated as a consequence

of an application that required real-time data reduction with

concurrent robot control [ 5 ]

To meet that need , a

multiprocessor configuration that included a physical common

memory entirely contained within a single Multibus chassis was

used. Each of the processors was a single-board computer. The

memory designated for common use by all processors was resident

on a separate board and had an address range that mapped into the

address space of each of the processors. Hence, local common

memory was defined to be a contiguous area of physical memory

accessible to two or more distinct processes within a single

computer system (Figure X-l).

The AMRF began work on an automated factory in 1981 [6]. The

AMRF automated factory concept held that the old idea of a single

huge computer controlling all machines in the factory was too

inflexible. Instead, computer processes such as control programs

would run on many different computers, of all sizes and models,

and might possibly be located in different buildings.

This extended the local common memory concept of the robot

control system in many ways. A major extension was the linking

and coordination of local common memories using network services.

That is, processes which had to communicate with each other were

often in separate backplanes and used different operating

systems. A single physical common memory was no longer possible

or practical, so each computer system had to have its own local

common memory. These common memories were connected using

network services that were transparent to the application

process. The linked local common memories established a global

common memory (Figure 1-2). The information contained therein

was considered to represent a global memory- resident database.

A discussion of the AMRF network architecture is beyond the scope

of this document. Detailed information about that architecture

is available in reference [7].

I 2
Common Memory for the PC

1-3

Figure

1-1.

Local

Common

Memory
Computer

System

Common Memory for the PC

I 4

Figure

1-2.

Global

Common

Memory
Common Memory for the PC

3. PURPOSE OF THIS SOFTWARE COLLECTION

The intent of this software is to provide a local common memory

environment for the IBM PC and compatibles. This generic group

of personal computers will hereafter be referred to as PC's..

Given the increasing speed (e.g., 25 MHz 80386 personal

computers) and capability (32 Mbytes of addressable space,

multitasking operating systems, etc) of the PC and its rapidly

decreasing price, it is feasible and desirable to consider the PC

for implementation as a networked real-time controller.

Providing the common memory for the PC is the first step in this

process

I 5
Common Memory for the PC

4. COMPUTER CONFIGURATION REQUIREMENTS

Computer configuration requirements are:

1. An IBM PC (or compatible) with at least 256 Kbytes of

memory and DOS operating system.

2. The C programming language. Although the Turbo C

(version 1.0) distribution was used during PC common

memory development. Turbo C dependencies were studiously

avoided — with one exception, identified in Section

IV. 1.4. The use of C enabled the creation of object

module libraries that can be used during the LINK process

to incorporate common memory into user processes written

in languages such as assembler, Prolog, FORTRAN, C and

others

I 6
Common Memory for the PC

II . OVERVIEW OF THE COMMON MEMORY ARCHITECTURE

The AMRF architecture of common memory and network communications

is fully described in [7]. The following subsections discuss

components of that architecture that are important to the

understanding of PC common memory.

1.

COMMON MEMORY COMPONENTS

1.1. Mailboxes and Mailgrams

All interprocess communication is accomplished through a

mechanism called "mailboxes". Mailboxes are logical storage

areas where messages (called "mailgrams") are placed by sender

processes and picked up by receiver processes. From the point of

view of the sender and receiver processes, the location of the

correspondents does not affect their communication.

Mailboxes reside in a special area of memory, designated as local

common memory. A common memory manager is responsible for

assigning and managing the local common memory area.

Local common memories can be combined into a global common memory

by implementing a unique common memory client process that

interfaces with another similar process on a remote host for the

purpose of exchanging common memory information. The physical

connections can be point-to-point or utilize various local area

network media, such as Ethernet or broadband. (Figure 1-2.)

The user interface to local common memory is discussed below.

1.1.1. Mailgram Format

By convention, mailgrams are placed into a mailbox beginning at

the lowest memory location allocated for the mailbox and continue

occupying bytes until either the entire mailgram is in the

mailbox or until all space allocated for the mailbox has been

filled. Except for adherence to this convention, there is no

standard format for a mailgram. There are, however, standard

information units which must be associated with each mailbox.

They are:

1. Length of the current mailgram in the mailbox,

2. Indication of a change in mailbox contents (discussed in

Section II.2.3.), and

3. Some type of mailbox access control mechanism (discussed

in Section II . 2

) The current level of the AMRF common memory architecture requires

that these information units must be present either in the

II 1
Common Memory for the PC

Byte 1 2 3

i i i

i i i Process-Dependent Text . . .

i i i

i i i

Figure 11-1. Generic Mailbox Structure

mailgram or be maintained with the mailbox by the common memory

manager. In general, if there is a common memory manager

available in a particular common memory implementation, then the

mailbox structure is shown in Figure XI-1.

However, when no common memory manager is present and these

entities are expressed in the mailbox area itself, then the

mailbox has the structure shown in Figure XI-2.

II - 2
Common Memory for the PC

Byte 1 2 3 4 5 6 7 8

j Write Lock

i

i

i Read Lock

i

i

i

i Sequence

i

i

i

i Length

!

9 10 11 12

Process-Dependent Text . . .

Write Lock Is a semaphore indicating current writer activity.

(i.e., If the write lock Is ON, then the mailbox

Is being written, and should not be read)

Read Lock Is a semaphore indicating current reader activity.

(i.e., if the read lock Is ON, then the mailbox is

being read, and should not be updated)

Sequence is a sequence number attached to the mail gram in

the particular mailbox. Every time the text of

the ma i

I gram Is changed, the sequence number is

Incremented. The update can be detected by

examining only the sequence field.

Length is the length of the ma i I gram in bytes.

Text Is the Information portion of the mailgram that is

defined entirely by the communicating processes.

Figure 11-2 . Special Mailbox Structure Used When

A Common Memory Manager Is Not Present

With reference to Figure II-2, the read and write locks are

considered to be part of the mailbox and not the mailgram. That

is, when the mailgram is read or written, the lock bytes are

manipulated in order to assure the integrity of the mailbox

access, but are not transferred to or from a user data storage

area. Furthermore, if a network interface process is to transfer

the mailgram to another network interface process located on a

different computer, the lock bytes are not transported.

II 3
Common Memory for the PC

Byte 1 2 3 4 5 6 7

i

i Sequence

i

i

i Length

i

i

Process-Dependent Text . . .

i i i

i i t i

Sequence is a sequence number attached to the mail gram in

the particular mailbox. Every time the text of

the mail gram is changed, the sequence number Is incremented so that the change can be detected by

examining only the sequence field.

Length is the length of the mail gram In bytes.

Text is the Information portion of the ma i I gram that is

defined entirely by the communicating processes.

Figure 1 1-3 . General Ma i I grant Format Used In A

Mixed Common Memory Environment

In a mixed global common memory environment, where some systems

have a common memory manager and others do not, the mailgram is

assigned the specific format depicted in Figure II-3. The system

with the common memory manager receives a mailgram with the

sequence number and the length byte included in what it considers

to be "process-dependent information". It is the responsibility

of the application reading from the mailbox to know the mailgram

format being used.

1.1.2. Mailbox and Mailgram Properties

(1) The mailbox must be created (or declared) before

mailgrams can be deposited into it or an attempt can be

made to read the mailbox contents.

(2) Every mailbox has a unique global name. The name is

assigned to the mailbox at the time it is created and

uniquely identifies the mailbox to all processes

participating in the global common memory. Remote

systems desiring a copy of the mailbox contents must have

a mailbox with the same name declared in their local

common memory. Network services perform the mailgram

transfers [ 7 ]

II 4
Common Memory for the PC

(3) Every mailbox contains an initial value assigned by the

creator when it is created. In some systems, this is a

standard value (e.g., all zeros); in other systems, this

value defaults to the contents of memory at the time of

creation.

(4) Every mailbox contains exactly one mailgram at any given

time. A mailgram stays in the mailbox, no matter how

often it is read, until a new mailgram arrives for that

mailbox. The new mailgram replaces the old one on

arrival, whether or not the old mailgram has ever been

read

(5) The mailbox writer decides when to replace the mailgram.

This may be performed independent of external information

or may be influenced by "flow control" factors.

(Section II . 2 .

)

(6) In general, only one process is authorized to write into

a mailbox at a time. In the case where more than one

process may write into a specific mailbox, implicit or

explicit "flow control" must be implemented.

( Section II . 2 .

)

(7) Any number of reader processes can retrieve the current

mailgram in a mailbox.

(8) Any reader process can pick up the same mailgram several

times if the writer does not change it in the interim.

Likewise, any reader process may miss several mailgrams

if the writer changes the mailgram more often than the

reader picks it up. When it is important to assure that

a particular recipient has read the mailgram before a new

one is issued, the writer and reader must agree to a

"flow control" protocol. (Section II. 2.)

The mailbox management mechanism guarantees that a new

mailgram will be distinct from its predecessors.

However, the mailbox management mechanism does not

guarantee that any particular receiver will have picked

up a mailgram before it is replaced. If it is necessary

to assure that a particular receiver has read the

mailgram before it is replaced, the sender and that

receiver must agree to a protocol by which the sender

refrains from replacing the mailgram until it has an

indication that the receiver has read it.

(9) Every mailbox has a fixed size which is defined when the

mailbox is created. There is no predefined maximum on

mailbox size; There may be a maximum mailbox size for

individual systems as a consequence of hardware or

II 5
Common Memory for the PC

software limitations. Any given mailbox must be large

enough to contain the largest mailgram agreed upon

between the sender and receiver (s).

(10) Mailgrams can be of variable length. Each mailgram has

associated with it information on how long it is. A

mailgram may never be longer than the mailbox in which it

is placed. If necessary, the mailgram will be truncated

before it is transferred into the destination mailbox by

the common memory service routines.

1.2. Common Memory Manager

Depending on the capabilities of the host operating system within

any computer (or single-board computer in a Multibus chassis), it

is possible to have an active common memory manager agent.

However, an active common memory manager is not absolutely

required. A passive manager is also possible.

1.2.1. Active Common Memory Manager

An active common manager is one that actively controls mailbox

access for each common memory client using either of the

following methods.

(1) Pass a token among the clients. The token might be

passed sequentially from client to client. Alternately,

the token could be held by the common memory manager;

when a client requests common memory access, he is given

the token. The token is returned to the manager when the

client has completed common memory access.

It is possible for the token to get lost. That is, if a

client that has been issued the token never returns it

(due to a program abort or unexpected endless loop), all

other clients are prohibited from further access. In

order to minimize the consequences of such a deadlock

situation, a token regeneration scheme must then be

developed to recognize when the token has been

unequivocally lost and a new token must be generated.

(2) Present a single interface to all common memory clients:

the manager's access interface. The manager then

coordinates, internally, the individual accesses of the

clients. This is somewhat similar to token passing,

where the token only passes between the manager and a

client, and never between two clients. However, it does

give the manager the flexibility of coordinating more

than one concurrent access

II 6
Common Memory for the PC

1.2.2. Passive Common Memory Manager

In the case of a passive common memory manager, there is no token

or single interface. Instead, there is an access convention that

is adhered to by all common memory clients. For example, the

robot controller referenced previously (Section 1.1.1.) uses a

scheme involving repetitive common memory access cycles [8]. In

this instance, there are three distinct divisions of the cycle:

(1) READ division: During the READ division all processes

(each of which exists on its own single-board computer)

compete for bus access in order to READ from common

memory mailboxes. No WRITE actions are performed during

this time period. The duration of this division is

fixed. All READ accesses that are not completed during

this time period are postponed until the next READ

division.

(2) PROCESS division: During this division, all data

reduction, equipment control and data acquisition occurs.

No READ or WRITE access to the mailboxes is performed.

Its duration is fixed.

(3) WRITE division: During the WRITE division, all processes

once again compete for bus access in order to WRITE to

common memory mailboxes. NO READ actions are performed

during this time period. The duration of this division

is fixed. All WRITE accesses that are not completed

during this time period are postponed until the next

WRITE division.

II 7
Common Memory for the PC

2. COORDINATING COMMON MEMORY ACCESS

Common memory environments can be susceptible to several problems

related to coordinating access to these areas. The following

subsections identify the potential problems and some possible

solutions. Section III of this document specifies the solutions

implemented in the PC common memory architecture.

2.1. Read While Write is Active

A process may be attempting to read information from a common

memory mailbox at the same time that a second process is

attempting to update that mailbox (or vice-versa). Consequently,

the reading process may get inconsistent information (e.g., the

current value of field A and the former value of field B).

To avoid this, one could:

(1) use a semaphore for each common memory buffer area (a

mechanism that supports single-process access to the

buffer). Some processors provide atomic "test and set"

operations which can be used as hardware semaphores

Unfortunately, the PC does not. Software semaphores,

using Dekker's algorithm [4], for example, can be

extended to provide mutual exclusion between any number

of processes.

(2) define a regular, recurring real-time interval and divide

it into a write-only period and a read-only period. Any

process not prepared to perform a write operation during

the write-only period would have to wait for the next

write-only period. The same restriction holds for readonly periods.

(3) pass a token among participating processes. The process

that has the token can perform any read or write

operation it wants. Fixed length or varying length time

quanta can be employed. Token passing has an unfortunate

drawback: if the process with the token halts (or appears

to do so), passing of the token becomes impossible and

all access to common memory is barred. In a fixed length

time quantum implementation, the token can be reissued by

some governing process after the expiration of the time

quantum (plus some extra "safety margin"); in a varying

length time quantum implementation, the recovery

algorithm is much less obvious.

II 8
Common Memory for the PC

(4) utilize a hardware architecture that does not support

interrupt processing. Once a processor has control of

the bus (and consequent access to common memory), no

other processor can interrupt. This assures that

overlapped access does not occur.

2.2. Update Frequency Exceeds Read Frequency

A process may update the common memory area more often than a

reading process is able to retrieve the information.

This may only be an "application-specific" problem. That is, if

the reader process only wants the "current" information (as from

a temperature sensor, for example), then the fact that any amount

of older information may have been missed is a moot point.

However, if it becomes important that the reader process have

access to each information set before it gets updated, then some

form of "flow-control" must be used.

For example, if the information set in a common memory mailbox

includes a unique identifier (a time stamp or sequence number),

then flow control could be implemented by defining a second

mailbox in the common memory area into which the reader process

could echo the unique identifier. When the writer of the

original information sees the echoed identifier in this second

common memory mailbox, it knows that it can proceed with the next

update.

This method of flow control is feasible when the reader process

can consume the information as fast as it is produced. However,

if the reader process is too slow, it can have negative

ramifications for the information writer. For example, if a

temperature sensor at a nuclear power plant is attempting to

report rapidly rising temperatures but is prohibited from

reporting the current temperature because the mailgram reader has

not acknowledged the previous temperature, undesirable sideeffects can result.

2.3. Read Frequency Exceeds Update Frequency

A process may read the data in the common memory area more often

than a writer process updates it. This can result in "old"

information unintentionally being considered "new" information.

In the case where the information happens to be a command such as

"hit nail on head with hammer", an undesirable number of

duplicate executions could be performed.

A possible solution is to identify new information whenever it is

placed into the common memory buffer by implementing a flag field

II 9
Common Memory for the PC

within the mailbox. This flag field could take the form of a

sequence number that gets incremented with each update of the

mailbox or a time stamp that identifies when the information was

placed into the mailbox. In each case, the reader process is

looking for a change in the flag field to indicate that mailbox

contents have been updated.

An alternative method is for the common memory manager to

maintain a list containing the names of mailboxes that have been

updated. A separate list is maintained for each common memory

application. The application can then be given the update list

upon request. By reading only the changed mailboxes, the

application can minimize unproductive time spent examining

unchanged mailboxes. However, this method is only available for

systems with an active common memory manager.

2.4. Multiple Readers of a Common Mailbox

In the case where a single mailbox is being accessed by multiple

readers, if it is important that each of the readers have the

opportunity to retrieve the mailgram before it is overwritten,

then a more elaborate form of flow control must be implemented.

One solution is to share a single "flow control" mailbox between

all the readers. Each reader sets a specific "flag" in the

mailbox indicating he has retrieved the message. When all flags

have been set, the shared-read mailbox contents can be

overwritten. This "solution" immediately introduces another

problem: multiple writers to a single mailbox. (See

Section II . 2 . 5 .

)

A simpler, more reliable solution is to assign each reader

process its own flow control mailbox.

2.5. Multiple Writers to a Common Mailbox

Unpredictable results can occur when more than one process is

permitted to write into a single common memory buffer:

(1) predicting the sequence in which information is written

to the common memory buffer may be impossible,

(2) guaranteeing that all reader clients have seen the

contents of the common memory buffer before it is updated

may be impossible, and

(3) identifying the intended reader client audience for any

particular memory buffer update may be impossible.

II 10
Common Memory for the PC

A simple solution is to stipulate that any common memory buffer

is permitted to have only a single process writing data into it,

although it can have any number of reader clients

More complex solutions that support the use of a single common

memory buffer by more than one writing process are possible. In

general, these solutions require the implementation of enhanced

flow control and flag field techniques.

II 11
Common Memory for the PC

3. MAILBOX MANAGEMENT

Mailbox management, as discussed in the following subsections,

applies only to implementations with an active common memory

manager. There are four fundamental common memory functions used

for mailbox management. They are: DECLARE, UNDECLARE, READ and

WRITE. Other AMRF extensions exist and are discussed in [7].

Passive common memory management involves the static designation

of specific memory areas for each mailbox. Although this might

be considered a DECLARE action, there is no equivalent UNDECLARE

action. Likewise, READ and WRITE access is uniquely different

from passively managed common memories (Section II.1.2.2.).

3.1.

DECLARE Access Requirements for Each Mailbox

Before an application can utilize a common memory mailbox for a

read or write operation, it must DECLARE the mailbox to the

common memory manager. Without this declaration, the common

memory manager will not allow access to the mailbox.

A declaration must be issued for each mailbox that is to be

accessed and must specify if the mailbox declaration is for a

READ function or for a WRITE function. If the mailbox does not

already exist in common memory, it is created and space is

allocated dynamically. The user application can declare the same

mailbox more than once.

There is no logical limit to the number of mailboxes that any

application may declare or access. Available memory and/or

memory addressing constraints impose the only limitation on the

number of common memory participants (applications), number of

mailboxes, and mailbox size.

3.2.

Perform the READ or WRITE Action

Using the common memory READ and WRITE functions, an application

can access the mailbox as often as desired. However, the

application must previously have declared that mailbox for the

respective access. The common memory manager will return a fatal

error status indication if the application is not a client of the

mailbox for the requested access.

3.3.

UNDECLARE Mailbox Access

After an application has completed all desired accesses to a

mailbox and before the application terminates, it should

undeclare all previously-declared mailboxes.

II - 12
Common Memory for the PC

When a user application undeclares a mailbox, the common memory

manager removes that application from the client list of the

mailbox. If the mailbox has other clients, no further action is

taken. However, if the mailbox has no other clients, it is

removed from common memory and the space it occupied is freed.

II 13
Common Memory for the PC

4. MAILBOX ACCESS METHODS

There are two possible mailbox access methods: implicit and

explicit

4.1. Explicit Mailbox Access

The word "explicit" is used to imply that there is no common

memory manager present. Predesignated, static memory areas are

assigned mailbox functions and are accessed directly by more than

one application for the purpose of exchanging information.

Since there is no memory manager agent, mailboxes and their

starting address and size are static and designated manually by a

human agent. The mailbox specifications are loaded (or coded)

into each participating application. Coordinating mailbox access

(Section II. 2.) is not a problem as long as interrupts are

disabled when any application accesses a mailbox.

This method of common memory access can result if:

(1) the participating processes are actually different states

within a single program,

( 2 ) the host operating system does not enforce a memory

protection scheme whereby a process is prohibited from

accessing memory allocated to a second process,

( 3 ) the host operating system supports the declaration of

"common" memory regions that can be shared by multiple

applications, or

(4) a Multibus implementation with multiple single-board

computers (SBC) is used together with a separate memory

board that maps into the address space of each SBC.

The mailgram format for explicit common memory would tend to

approximate Figure II-2 in order to clearly and easily identify

new information and coordinate mailbox access.

4.2. Implicit Mailbox Access

When the implicit method is used, each process associates an

internal "logical unit number" (or numeric handle) with a common

memory mailbox. This logical unit number is supplied to the

process when it creates the mailbox through the respective common

memory service. The process then references the logical unit

number when it performs READ or WRITE operations in order to

exchange mailgrams with the common memory.

II 14
Common Memory for the PC

The memory location of the mailbox is never accessed directly by

any of the participating processes. Instead, the common memory

manager has the responsibility of transferring data between the

mailbox and the user data area. This activity is performed

whenever the application requests a READ or WRITE.

4.3. Conversion of Implicit to Explicit Access

and Explicit to Implicit Access

Programs designed for explicit access can be moved to an implicit

access environment by inserting the necessary CM_READs

,

CM_WRITEs , and CM_DECLAREs to create the mailbox. CM_UNDECLARE

are recommended to discontinue mailboxes after their usefulness

has expired.

Likewise, programs designed for an implicit mailbox access

environment can be moved to an explicit environment by removing

the CM__DECLARE , CM_READ, CM_WRITE and CM_UNDECLARE sections and

replacing them with the necessary code to identify and access

target mailbox memory areas.

II 15
Common Memory for the PC

5. EXISTING COMMON MEMORY IMPLEMENTATIONS

5.1. Common Memory Maps into the Process 1 s

Address Space

In order to reduce the time needed to access areas of common

memory, the most desirable implementation is one where the common

memory occupies memory in the addressable range of the process.

Additional processes within the same "computer" can have access

to this same common memory area as long as they have a means of

directly accessing that same address space.

The word "computer" is placed in quotes in the preceding

paragraph because the reference can be to a single computer such

as the Digital Equipment Corporation VAX. It can also refer to a

collection of single-board computers resident in a single

Multibus chassis.

Within the VAX, the common memory areas can be included in memory

space of multiple processes, all active concurrently, by linking

to them as a shared READ or WRITE memory area.

For Multibus systems, the local common memory maps into the

address space of each of the single-board computers sharing the

same bus. Each process within its respective single-board

computer sees that memory as its own, and is able to access it

directly for READ or WRITE purposes.

5.2. Common Memory as a Separate Process

Some multitasking computer systems used within the AMRF are not

immediately amenable to sharing memory space with other active

processes. By altering the operating system, it is possible to

make them amenable. However, it is actually easier (and safer)

to create a separate common memory task.

The common memory information is then transferred between a

subset of information maintained by the (user) application

process and the actual common memory maintained by this separate

task. The interprocess communication is performed using

Transmission Control Protocol (TCP) routines [9].

II 16
Common Memory for the PC

5.3. The Global Common Memory

Information is exchanged with other common memory systems

implemented on remote computer hosts via another process resident

on the local host, called the network interface process (NIP)

[7]. The NIPs have access to all of their local common memory.

Connected to each other over a network, NIPs are able to transfer

information between common memories. (Figure 1-2)

Except for the time delays associated with the transfer of the

information across the network, the processes accessing the

common memory have no knowledge of what is actually happening to

the information that they provide or access.

II 17
Common Memory for the PC

6 . SUMMARY

6.1. Common Memory - An Application Interface

The result of this implemented architecture is that common memory

is an application interface to communications with any other

processes, both local and remote. It provides a uniform and

portable interface for every application. If the application is

later moved to a new location, no code changes need to be made

for any of its correspondents in order to continue data

exchanges. Some changes to the moved application may be

necessary if the new location provides a different hardware or

operating system architecture. The location changes are reported

to the network service and the network service adjusts the

mailgram delivery paths [7].

Providing a single application interface allows the application

developers to concentrate on the application and frees them from

the dependencies of the host-dependent interprocess

communication, including network communication.

Further benefits of the common memory interface are listed in the

following subsection. This is followed by a short discussion of

some perceived drawbacks to common memory as an application

interface.

6.1.1. Benefits of Common Memory

The benefits that common memory provides are listed below. Only

benefit 3 relies on the availability of network services.

However, all benefits are enhanced by the availability and use of

network services.

(1) Asynchronous communications occur between processes. The

application process is not interrupted by communications

from other processes. It accesses the desired

information whenever necessary (i.e., whenever it is

ready for it).

(2) Information can be shared with additional processes with

a minimum of effort. Additional processes can read from

the same areas of common memory without any action on the

part of the initial information provider to deliver it.

( 3 ) Communication is independent of the location of related

processes. The application process does not need to know

the location of any other process with which it

communicates. If the second process is within the same

processor, it is directly connected to the same common

II 18
Common Memory for the PC

memory. If the second process is located remotely, it

has its own common memory with which it communicates

Network services provide the connectivity between common

memories

(4) It supports coordinated activity between independent

processes. Two processes can coordinate their activities

by using common memory for command/ status information,

independent of their respective locations.

(5) It supports independent evolution of individual

processes. With the structured interface between

processes that common memory provides, individual

processes may evolve in response to changing requirements

without mandating equivalent changes in other processes

interconnected through the common memory (including the

network interface process.)

(6) It provides a consistent communications methodology for a

diverse collection of computers and operating systems.

Application processes are freed from machine-dependent

communication primitives (e.g., subroutine calls) for

both interprocess communications and network

communications

6.1.2. Drawbacks to Common Memory

No paper has yet been published discussing the drawbacks of

common memory although one is in preparation [10]. The following

are a few thoughts based upon personal experience and do not

represent any consensus of opinion.

(1) The reader of a mailgram does not know the state of the

writer of that mailgram:

(a) Is the writer on a local or remote host?

(b) Is the writer still active or has it terminated or

been aborted?

(c) Is the logical network connection linking the

applications, if applicable, still established?

(2) The writer of a mailgram does not know the state of the

reader of that mailgram:

(a) Is the reader on a local or remote host?

(b) Is the reader still active or has it terminated or

been aborted?

(c) Is the logical network connection linking the writer

with the reader, if applicable, still established?

(d) Has the reader retrieved the mailgram yet?

II 19
Common Memory for the PC

(3) Why use common memory at all if the correspondents are

all known to each other and the number of correspondents

and their location will never change? Other

communications techniques, such as network message

passing, would be more efficient.

With the exception of item (3), these concerns are associated

with the delivery and receipt of mailgrams. To some extent, they

are answerable with the implementation of a mailbox to

acknowledge the receipt of message similar to the flow control

mailboxes discussed in Section II. 2. However, they actually

extend beyond that level of concern.

For example, if a control process is waiting for a data report

that originates from a sensory process at irregular time

intervals, it is important for the control process to know

whether the sensory process is ever going to deliver the next

data report. Simply knowing that the sensory process has not

halted or been aborted may not be enough: it may be stuck in an

unintentional/undesirable endless loop! Perhaps it is necessary

for the sensory process to provide a "heartbeat" status in a

mailbox?

On the other hand, a sensory process that reports status into a

common memory mailbox may not have been programmed to care

whether the deposited information is ever read.

This list of drawbacks identifies part of the next logical

evolution (or extension) of the common memory architecture.

Each drawback is only a minor obstacle that can easily be

overcome by having the necessary information provided in common

memory, either by the common memory manager or by one or more of

the participating processes.

Item (3) raises a good question. The value of common memory as

an application interface in a manufacturing or production

environment where configuration changes are extremely infrequent

has yet to be determined. However, in a research environment

where applications evolve and shift from one host system to

another and from one architecture to another, the flexibility of

common memory has proven invaluable, for all the reasons listed

in Section II. 6. 1.1. Some alternatives to common memory are

identified in the following section.

6.2. Alternatives to Common Memory

Simple alternatives that encompass a single computer and

networking architecture are easily identified and implemented.

Significant difficulty arises when dissimilar architectures

comprise the applications environment. In those environments.

II 20
Common Memory for the PC

the user process is responsible for providing for all

communications mechanisms, including gateway routing to devices

connected to dissimilar networks.

The variety of hardware and software systems implemented in the

AMRF preclude the use of any simple common solution to provide

the same service as common memory. Communications among

processes within a single computer system would have to use

facilities provided by the operating system (if any), or new

capabilities similar to those provided by common memory would

have to be developed.

Attempts to use services provided by commercially-available

network solutions would also be difficult. Commercial network

solutions are not available for all computer systems in use in

the AMRF. Although more applications (solutions) using the

TCP/IP protocol are becoming available all the time, the current

migration for networks in manufacturing environments is towards

the Manufacturing Automation Protocol (MAP) and the Technical and

Office Protocol (TOP). With network companies concentrating on

major computer systems at this time, MAP and TOP products are not

available for all computer systems.

Any alternative to common memory that must provide service to

multiple applications located on several computer systems

distributed across multiple network topologies is most likely a

connection-oriented message passing solution. For example,

although TCP/IP is connectionless, MAP and TOP are connection

oriented

In a connection-oriented network, application process 'A*

establishes and maintains a connection to application process ' B'

for the bi-directional exchange of messages. Any new application

introduced into this environment will have to be accommodated

through code changes in those applications with which it must

communicate to provide for the additional connection and

messages

II 21

Common Memory for the PC

III. PC COMMON MEMORY ARCHITECTURE DESCRIPTION

This section describes the common memory architecture as it is

implemented for the personal computer using the DOS operating

system. Hardware and operating system limitations were the most

influential factors affecting the architecture's development.

Extensive effort was made to avoid operating system and hardware

dependencies in order to maximize portability to other computer

architectures and operating systems.

The presentation of specifications in the following sections

assumes that the reader has previously become familiar with

Section II and the general common memory architecture.

1. MAILBOXES AND MAILGRAMS

1 . 1 Coordinating Common Memory Access

This topic was originally discussed in Section II. 2. The

following subsections identify the solutions specifically adopted

for the PC common memory without further reference to the

problems or alternative solutions.

1.1.1. Read While Write is Active

Coordinating multiple accesses to a common memory mailbox in the

PC architecture approximates token passing. DOS is a single-user

operating system, so the common memory code is incorporated as

"in-line" code to the user application. Likewise, if the user

wishes to include other capabilities, such as a network interface

program, they too must be included as inline code. (An example

of this is shown in Appendix D.) This results in a single

program or application when viewed from the DOS perspective.

This single application will not interrupt itself to access

common memory. As incorporated in the preceding paragraph,

neither will the network interface process interrupt either

itself or the user application. Effectively, when any section

of the program accesses the common memory, it can be considered

to "have the token". The token can only be lost as a consequence

of a program crash; appropriate recovery and application

debugging steps must be taken following abnormal program

terminations

Other methods (i.e., local software development as well as

possible commercial offerings) of implementing multitasking

within DOS were considered. They were avoided because they were

operating system specific and significantly compromised the

portability of the common memory application to other hardware or

operating systems.

Ill 1
Common Memory for the PC

1.1.2.

Update Frequency Exceeds Read Frequency

The PC common memory takes a totally passive role in implementing

flow control. The decision to avoid flow control by the common

memory manager is intentional: common memory should function just

like computer memory. An application can access a mailbox for

read or write purposes as often as it desires. The READ

operation will retrieve whatever was deposited last, all prior

contents having been overwritten.

If flow control is important to processes exchanging information,

then it is the responsibility of the respective application

processes to provide for it. (Refer to Sections II. 2. 2 and

II. 2. 5. for further discussion about flow control.) 1.1.3.

Read Frequency Exceeds Update Frequency

The PC common memory manager maintains a separate linked list of

updated mailboxes for each application process that is a client

of common memory. The application process can then be given the

update list upon request, thereby providing an indication of

mailgram update without the overhead of a mailgram transfer. By

reading only the changed mailboxes, the application processes

minimize unproductive time spent examining unchanged mailboxes.

1.1.4.

Multiple Readers of a Common Mailbox

As stated in Section III. 1.1. 2, the PC common memory takes a

totally passive role regarding flow control. It is the

responsibility of the application processes to coordinate the

mailgram update procedure if it is desirable that each

application have the opportunity to retrieve a mailgram before it

is updated.

1.1.5.

Multiple Writers to a Common Mailbox

The PC common memory allows more than one application to write to

a mailbox. If only one application is to have access to a

mailbox for WRITE access, then that application must request

exclusive WRITE access when declaring the mailbox.

One potential future extension to PC common memory is to provide

for an "access list": the application originally declaring the

mailbox is considered to "own" it and may grant other

applications READ/WRITE access to its mailbox.

Ill ~ 2
Common Memory for the PC

Byte 1 2 3

i i i

i i i Process-Dependent Text . . .

i i i

i i i

Figure MI-1. Generic PC Mailbox Structure

Coordinating writer access in order to avoid a mailgram deposited

by one writer from being overwritten by another writer before it

has been retrieved by any reader is the responsibility of the

user application. The PC common memory takes a totally passive

role regarding mailbox flow control.

1.2. Mailgram Format

The PC common memory architecture assumes a mailbox structure as

shown in Figure III-l.

However, since PC application processes may need to communicate

with other applications resident on systems without a common

memory manager, the assumed mailbox structure is as shown in

Figure III-2. Since the PC common memory manager does not know

which mailgram format is in use, it does not manipulate or

monitor any of the fields of this alternate mailgram format.

It is the responsibility of the user application reading from the

mailbox to be knowledgeable about the mailgram format and the

mailgram contents. Furthermore, it is the responsibility of the

user application to update and/or provide the information in the

SEQUENCE and LENGTH fields in accordance with AMRF conventions.

That is, the sequence number must change each time the mailgram

is intended to be considered "new". Writing a mailgram with an

unchanged sequence number but different process-dependent text

may result in the mailgram not being read by an application on a

host system that does not have an active common memory manager.

The LENGTH field specifies the number of bytes in the processdependent section of this mailgram format. A process performing

a READ request with PC common memory is returned the total length

of the mailgram, including the SEQUENCE and LENGTH field sizes.

This number is expected to be different from the value of the

LENGTH field in the mailgram.

Ill 3
Common Memory for the PC

Byte 1 2 3 4 5 6 7 . . .

i i t i i i i i i

i i i i i i i i i

! Sequence ! Length ! Process-dependent Text . . .

Sequence is a sequence number attached to the mall gram in

the particular mailbox. Every time the text of

the mail gram is changed, the sequence number is

Incremented, so that the change can be detected by

examining only the sequence field. The numeric

representation Is unsigned binary integer, and

"wraps" back to zero when the maximum integer

representation is Incremented.

Length is the length of the process-dependent text In the

mall gram in bytes. The numeric representation is

unsigned binary integer.

Text is the information portion of the maligram,

defined entirely by the communicating processes.

Figure ! i 1-2 , Underlying PC Ma 1

8 gram Format
Common Memory for the PC

2. COMMON MEMORY ACCESS METHOD

The PC common memory is implemented using the implicit common

memory access method. All mailbox access is performed indirectly

through calls to common memory manager routines

Ill 5
Common Memory for the PC

3. MAILBOX MANAGEMENT

The following subsections describe the software interfaces that

support explicit common memory, as implemented on the PC. There

are four fundamental common memory functions: DECLARE, UNDECLARE,

READ and WRITE. Two additional functions, CKMAIL and DISC, have

been provided in the PC version of common memory in order to

expedite memory access and management, and are also discussed.

3.1. DECLARE Access Requirements for Each Mailbox

Before an application can utilize a common memory mailbox for a

READ or WRITE operation, it must DECLARE the mailbox to the

common memory manager. Without this declaration, the common

memory manager will not allow access to the mailbox.

A declaration must be issued for each mailbox that is to be

accessed. However, the application may issue multiple types of

access for the declared mailbox within the same mailbox

declaration (Appendix B).

If the mailbox does not already exist in common memory, it is

created and space is allocated dynamically. The common memory

manager maintains two separate lists of clients for each mailbox:

a list of reader clients and a list of writer clients. If access

is granted, the user application is registered on the appropriate

list in accordance with the requested access.

The user application can declare a mailbox more than once.

Subsequent declarations for the same mailbox are assumed to be

requests to change the application^ access rights. That is,

these requests can ADD an access that was not previously

requested, or CHANGE an existing access. A particular access can

only be removed by undeclaring it.

For example, a " XREAD | WRITE" declaration for a mailbox followed

by an "READ" declaration results in an access of "READ | WRITE"

The character "

| " is used to represent a bit-wise OR of the bit

representations associated with the specific access function.

(The result assumes that a non-fatal error status is returned

from function cm_declare)

There is no logical limit to the number of mailboxes that any

application may declare or access. Available memory and/or

memory addressing constraints impose the only limitation on the

number of common memory participants (applications) and

mailboxes

Ill 6
Common Memory for the PC

3.2.

Perform the READ or WRITE Action

Using the common memory READ and WRITE functions, an application

can access the mailbox as often as desired. However, the

application must previously have declared that mailbox for the

respective access. The common memory manager will return a fatal

error status if the application is not on the client list of the

mailbox or has not been granted the requested (READ or WRITE)

access

3.3.

UNDECLARE Mailbox Access

After an application has completed all desired accesses to a

mailbox and before the application terminates, it should

undeclare all previously-declared mailboxes. This can be done

individually for each mailbox, or all mailboxes can be undeclared

through a Disconnect request.

When a user application undeclares a mailbox, the common memory

manager removes that application from the client list of the

mailbox. If the mailbox has other clients, no further action is

taken. However, if the mailbox has no other clients, it is

removed from common memory and the space it occupied is freed.

3.4.

Mailbox Management Extensions

The PC common memory architecture provides two notable extensions

to the standard mailbox management services . These are provided

in order to meet mailbox access coordination criteria and to

simplify the mailbox management process.

3.4.1. Disconnect the Application from Common Memory

If an application intends to terminate its involvement in the

common memory, it should undeclare all of its mailboxes. The

Disconnect function provided by the common memory manager reduces

this to a single request. When an application issues a

disconnect request, the common memory manager undeclares all

mailboxes for that application.

This function is provided in order to simplify and expedite the

departure of an application from the common memory environment.

Well-behaved applications can be expected to undeclare their

mailboxes either individually or via the Disconnect function.

However, in some future multitasking environment, it is

conceivable that some task participating in common memory may

abruptly terminate. It will be the responsibility of the common

memory manager to detect the abnormal termination of the process

III 7
Common Memory for the PC

("how" will depend on the specific operating system) and

undeclare all of that process's mailboxes, thereby purging the

common memory of unnecessary mailboxes (i.e., mailboxes to which

no other process has declared access).

3.4.2. Check for Mail

Since common memory mailboxes serve as a communications

interface, it is important to know when (or whether) new

information has been deposited in any mailbox. As mentioned

previously (Section IIX.1.1.3.), a mechanism exists within the PC

common memory architecture to identify new information.

Rather than force every application participating in the common

memory to examine each of its mailboxes to discover new data, the

PC common memory manager maintains a list of mailboxes that have

been updated. The application can simply check its mail and is

presented with a list of mailboxes that have changed. The common

memory manager then starts a new list. The application can now

limit its READ requests to those mailboxes whose contents have

changed, and thereby minimize the amount of CPU time spent

looking at common memory mailboxes.

If the application performs a READ of a mailbox for which there

is an entry on the update list (i.e., without checking for mail

first), the update list entry for that mailbox is removed by the

common memory manager.

Ill 8
Common Memory for the PC

IV. PROGRAMMER REFERENCE

The common memory library was developed using the C programming

language, as specified by Kernighan and Ritchie [1]. The

C programming language was selected in order to maximize

portability to other computer architectures

11.1. . IMPLEMENTATION ISSUES

The Compiler

The Turbo C (version 1.0) small memory model compiler was used

[2,3]. Users who wish to use a different compiler model may need

to recompile the common memory library in order to have a

consistent data structure definition for variables such as

pointers. Defaults are used in the common memory library in

order to facilitate such redefinition.

1.2.

Memory Allocation and Usage

The common memory manager uses linked lists extensively to

maintain information about its clients and their associated

mailboxes. The memory space for these data structures is

allocated and freed dynamically using functions MALLOC and FREE,

respectively. The MALLOC function allocates memory space

directly from the user static data area. In the small model, the

user application is given 64 Kbytes of static data space.

The 64 Kbyte limit is an artificial one, however, since data

space outside of that 64 kbyte can be dynamically allocated and

freed using functions FARMALLOC and FARFREE. However, these

functions are specific to MS-DOS, and it is desirable to avoid

such dependencies.

The amount of data space available to the application process

varies with the compiler memory model used. The compact and

large models, for example, provide for up to 1 Mbyte of static

data space. If the user prefers to use the small memory model

(perhaps because compiling is faster), it is preferable that the

user application perform the FARMALLOC and FARFREE in order to

continue the current level of common memory library independence.

1.3.

Interfaces to Languages Other Than C

The common memory library was developed using the C programming

language. This does not preclude software developers, who wish

to use another programming language compiler for their

application, from linking with the library.

IV 1
Common Memory for the PC

For example, the Turbo C user's guide [2] discusses how to link

Turbo Pascal and Prolog programs with C object modules.

Likewise, it may be feasible to link this C version of the common

memory library to other languages, such as Lisp and Ada. This

will depend on the compiler implementation. The interested

reader must research the respective language reference manual (s).

1.4. Non-portable Common Memory Functions

Only one function referenced in the library is not immediately

portable to other C language compilers . This is function

"eprintf". It is located in file cm_utilSoC, and is used by the

common memory functions to print debugging statements. Its

specificity is to Turbo C and is based on its use of a variablelength argument list. However, other (but not necessarily all) C

compilers are known to support variable-length argument lists, so

recoding this function to comply with another compiler should not

be too difficult.

IV - 2
Common Memory for the PC

2. THE COMMON MEMORY INTERFACE LIBRARY

The common memory library provides three service categories:

(1) functions that provide common memory access, (2) functions

that provide information about common memory usage, and

(3) convenience functions. These service categories are described

in detail below.

The library distribution kit consists of two INCLUDE (source)

files and two object files. The user application must include

the source files during the application program compilation

period (described in Section IV. 5.2). The object files are

linked during the application program linking period (described

in Section IV. 5. 3). Section IV. 5.1. lists files in the

distribution kit.

The source files and the object files have an embedded variable

that identifies the common memory library version number. It is

critical that both version numbers be identical in order to

insure the proper performance of the common memory interface.

Section IV. 4. 3. details how to determine the respective version

numbers

The common memory interface descriptions shown below incorporate

the C language convention that a function returns a value through

a RETURN statement. These returned values are of type SHORT INT

(2 bytes) and report a completion status for each routine.

Appendix A lists all possible status codes and describes their

significance.

The library routines utilize various data structures to contain

and convey specific information to the user application. In the

following pages, the data structure for each argument of the

functions is identified. This identification is prefaced by the

word "TYPE". The data structures are detailed in Appendix C.

2.1. Introduction to Common Memory Manipulations

The actual functions that provide access to common memory are

presented in subsequent pages. Before using these functions, it

is necessary to have an understanding of the relationship they

have to each other and the sequence in which they must be

accessed. Section III. 3 describes this relationship.

IV 3
Common Memory for the PC

2.2. Functions That Provide Common Memory Access

This section describes the functions that provide common memory

access. Only four of them (cm_declare, cm_undeclare, cm_write / and cm_read) are actually necessary. The others provide

expeditious extensions to these basic functions. (For example,

cm__disc will undeclare all mailboxes previously declared by the

user process, thereby relieving the user from having to submit a

series of cm_undeclare ' s .

)

The argument list for each function is described in detail. Each

function returns an integer status value that correlates with

what the function is to perform (hence the ' int' before each

function name) . The list of all potential status values that

this family of functions can return and their significance is

provided in Appendix A.

IV 4
Common Memory for the PC

2.2.1. Function cm_declare

This function creates the

mailbox client structures

necessary application, mailbox, and

within common memory to support future

mailbox manipulations by the declaring application.

If an application calls cm_declare for an existing mailbox for

READ or XREAD access, the common memory manager will NOT place an

entry into its "update list" for that mailbox. The purpose of

the update list is to indicate that the mailbox contents have

been written SINCE the time of the cm_declare or cm_read. It is

assumed that the user application will perform an initial cm_read

as a matter of course.

int cm_declare ( fsm - INPUT

TYPE char *fsm

user application name string.

String must be null-terminated

and must be less than or equal to

32 characters in length

(excluding the trailing NULL).

mbxname - INPUT

TYPE char *mbxname

mailbox name string. String must

be null-terminated and must be

less than or equal to 32

characters in length (excluding

the trailing NULL).

mbxsize - INPUT

TYPE int mbxsize

max size of mailbox to be

created

mbxaccess - INPUT

TYPE int mbxaccess

Potential vales are

READ | WRITE | XREAD | XWRITE

but not both of the same kind in

the same declaration. The

associated constants are

listed in cm_const.h.

mbxhandle - OUTPUT

TYPE int *mbxhandle

Value returned in the integer

variable is used as a shorthand

reference for mailbox for calls

to all other cm routines.

) RETURNS: status, as identified in cm const.

IV 5
Common Memory for the PC

2.2.2. Function cm_undeclare

Function cm_undeclare is used to remove a user application from a

particular mailbox's client list for the specified access. More

than one access type may be specified at each call, subject to

the access rules identified in the cm_declare section.

If the undeclare action results in a mailbox without any clients,

that mailbox is deleted and the space returned to the operating

system. Likewise, if the action results in a user application

that has no other mailbox's declared, that user application is

removed as a common memory client.

If the deleted mailbox is referenced on the undeclaring user

application's update list, that specific update entry will also

be deleted.

int cm_undeclare( fsm - INPUT

TYPE char *fsm

user application name string.

String must be null-terminated

and must be less than or equal to

32 characters in length

(excluding the trailing NULL).

mbxaccess - INPUT

TYPE int mbxaccess

Potential values are

READ I WRITE | XREAD | XWRITE,

but not both of the same kind in

the same declaration. The

access constants are

listed in cm_const.h.

mbxhandle - INPUT

TYPE int *mbxhandle

Variable value was initially set

by cm_declare and is used as a

fast way to reference a specific

mailbox. Although this does

not need to be a pointer, it is

specified as such for

compatibility with cm_declare

(which requires it) and other

common memory routines.

) RETURNS : status, as identified in cm const.

IV - 6
Common Memory for the PC

2.2.3. Function cm_write

Function cm_write is used to transfer a specified number of bytes

from the user data area to the common memory mailbox. As a

consequence of the write operation, all user application's that

have declared READ (or XREAD ) access to this mailbox will have an

entry made on their update list.

int cm_write ( fsm - INPUT

TYPE char *fsm

user application name string.

String must be null-terminated

and must be less than or equal to

32 characters in length

(excluding the trailing NULL).

mbxhandle - INPUT

TYPE int *mbxhandle

Variable value was initially set

cm_declare and is used as a fast

way to reference a specific

mailbox. Although this does not

need to be a pointer, it is

specified as such for

compatibility with cm_declare

(which requires it) and other

common memory routines.

usr_data - INPUT

TYPE byte *usr_data

points to user data area from

which bytes are transferred.

nr_bytes - INPUT

TYPE int *nr_bytes

int variable contains nr of bytes

to be transferred from user data

area to common memory. Although

this does not need to be a

pointer, it is specified as such

for compatibility with cm_read,

which requires it.

) RETURNS: status, as identified in cm const.h

IV - 7
Common Memory for the PC

2.2.4. Function cm_read

Function cm_read is used to transfer a specified number of bytes

to the user data area from the common memory mailbox. It is

recommended that cm_ckmail be used together with cm_read to

minimize unnecessary common memory accesses.

If an entry for this mailbox exists on the update list of this

user application, it is removed at completion of the cm__read

operation.

int cm read (fsm

mbxhandle

usr data

nr_bytes

- INPUT

TYPE char *fsm

user application name string.

String must be null-terminated,

and must be less than or equal to

32 characters in length

(excluding the trailing NULL).

- INPUT

TYPE int *mbxhandle

Variable value was initially set

cm_deelare and is used as a fast

way to reference a specific

mailbox. Although this does not

need to be a pointer, it is

specified as such for

compatibility with cm_declare

(which requires it) and other

common memory routines.

- INPUT

TYPE byte *usr_data

points to user data area from

which bytes are to be

transferred

- INPUT/OUTPUT

TYPE int *nr_bytes

When cm read is called, if :

( 1 ) ¥he int variable = 0 , then

all data bytes are

transferred from the

mailbox to the user's data

area

(2) the int variable is not

equal to 0 , the nr of

bytes transferred will be

the minimum of (nr__bytes,

nr bytes__in_mbx )

.

IV - 8
Common Memory for the PC

RETURNS

Upon return, the variable pointed

to by nr_bytes will contain the

actual number of bytes

transferred. If fewer bytes are

transferred to the user data area

than are available in the

mailbox, an "information- only"

status of I_CM_MOREDATA is

returned to alert the user who

may have inadvertently called

cm_read without clearing the

variable pointed to by nr_bytes

It is the user's responsibility

to make sure that the data area

is large enough to contain the

mailgram.

)status, as identified in cm const.

IV - 9
Common Memory for the PC

2.2.5. Function cm_ckmail

For each user application that is a READer client of common

memory, the common memory manager creates and maintains a list of

those mailboxes that have changed since the last time the user

application read them (i.e., an update list). Whenever a user

application writes to a common memory mailbox, the common memory

manager posts an entry on this "update" list. If an entry

already exists for a changed mailbox, no additional entry is

made. The list is maintained in first-in-first-out (FIFO) order.

Entries are removed from this list when a user application calls

cm_read for the respective mailbox or when the application calls

cm_ckmail. If an update list exists, cm ckmail returns a pointer

to the top of the list and releases the list to the application.

If no update list exists, cm__ckmail returns NULL. (If a list is

passed to the user application, the common memory manager will

start a new list when the next mailbox update arrives.)

Once the list is released to the user application, it is the

responsibility of the user application to FREE the memory

allocated for the list.

Using the update list, the user application can now perform

sequential cm_read operations and only access those mailboxes

that have changed since the last read operation.

int cm_ckmail (fsm - INPUT

TYPE char *fsm

user application name string.

String must be null-terminated

and must be less than or equal to

32 characters in length

(excluding the trailing NULL).

listjptr - INPUT

TYPE is

struct update_list **list_ptr;

If an update list exists for this

user application, cm_ckmail will

return a ptr to the top of the

update list in this location. If

none exists, cm_ckmail will

return NULL.

(continued on next page)

IV 10
Common Memory for the PC

nr_entries - INPUT

TYPE int *nr_entries

If an update list exists, the int

variable will contain the number

of entries in the update list;

else, it will contain ZERO.

) RETURNS: status, as identified in cm const.

IV 11
Common Memory for the PC

2.2.6. Function cm_disc

Function cm_disc provides a shortcut method for a user

application to undeclare all of its mailboxes at one time. All

data structures within common memory that are associated with

that user application are freed. The user application must issue

a cm declare before it can again access common memory variables.

int cm_disc (fsm - INPUT

TYPE char *fsm

user application name string.

String must be null-terminated

and must be less than or equal to

32 characters in length

(excluding the trailing NULL).

) RETURNS s status, as identified in cm const »h

IV 12
Common Memory for the PC

2.3. Functions That Provide Information About Common

Memory Usage

The following functions provide a "window" into the common memory

environment. They are available to any application. In fact,

applications that are not participating in common memory (i.e.,

applications that do not have any mailboxes declared) can use

these calls to determine common memory activity.

These functions were intended for use during the common memory

development process. During that time, it was determined that

they would be useful for reporting local common memory status to

some supervisory and/or monitoring agent (located either across

the network or on the local host).

IV - 13
Common Memory for the PC

2.3.1. Function cm_get_fsm_list

This function allows any user application to determine what user

applications are currently active in common memory. Using the

mbxname and list_type function arguments appropriately, the

caller can retrieve the list of all user applications known to

the common memory manager or only the list of clients (read or

write) for a specific mailbox. The information that is returned

on the list can be used to solicit other user application (and,

indirectly, mailbox) statistics.

int cm_get_fsm_list

(

mbxname - INPUT

TYPE char *mbxname

If NULL, this routine will

return, through fsm_list_ptr , the

list of all user application

names known to the common memory

manager. Argument "list_type"

has no effect. If not NULL, it

must point to a mailbox name.

This routine will return a list

of all user applications that are

a client of that specific

mailbox. The argument "list_type"

is used to qualify whether the

caller wants the list of READer

clients or the list of WRITEr

clients

list_type - INPUT

TYPE char

May only have the values 'R'

(READ) and 'W' (WRITE) when

*mbxname is non-NULL. If

*mbxname is NULL, list__type is

ignored

fsm_list_ptr - OUTPUT

TYPE struct fsm_l i s t_type

**fsm_list ptr

This routine wilT create a linked

list of user application names

and return a ptr to the top of

the list if any user applications

exists or NULL if none exist. It

is the user's responsibility to

free this list when it is no

longer needed.

IV 14
Common Memory for the PC

int_ptr - OUTPUT

TYPE int *int_ptr

Upon return, the int variable

will equal the number of entries

in the list.

) RETURNS: status, as identified in cm const.h

IV 15
Common Memory for the PC

2.3.2. Function cm_get_mbx_list

This function allows any user application to determine what

mailboxes (mbx) are currently active in common memory. The

information that is returned on the list can be used to solicit

other common memory user application (and, indirectly, mailbox)

statistics. Using the fsm and list_type function arguments

appropriately, the caller can retrieve the list of all mailboxes

in common memory, or only the list of mailboxes (read or write)

for a specific user application.

int cm_get_mbx_list

(

fsm - INPUT

TYPE char *fsm

user application name string.

String must be null-terminated

and must be less than or equal to

32 characters in length

(excluding the trailing NULL).

If NULL, this routine will

return, through mbx_l±st_ptr , the

list of all mailbox names known

to the common memory manager.

Argument "list__type" has no

effect. If not NULL, it must

point to a user application name.

This routine will return a list

of all mailboxes that are a

declared by that user

application. The argument

,e list_jtype" is used to qualify

whether the caller wants the list

of READer mailboxes or the list

of WRITEr mailboxes.

list__type - INPUT

TYPE char

May only have the values 'R'

(READ) and ' W

' (WRITE) when *fsm

is non-NULL. If *fsm is NULL,

list__type is ignored.

mbx_list__ptr - OUTPUT

TYPE struct mbx__list_type

* *mbx_i i s t_pt

This routine will create a linked

list of mailbox names and return

IV - 16
Common Memory for the PC

a ptr to the top of the list if

any mailboxes exist, or NULL if

none exist. It is the user's

responsibility to free this list

when it is no longer needed.

int_ptr

) RETURNS: status, as identified in cm const.

- INPUT

TYPE int *int_ptr

Upon return, the int variable

will equal the number of entries

in the list.

IV 17
Common Memory for the PC

2.3.3. Function cm_get_cm_stats

This function provides common memory operating statistics. Since

the size of the statistics areas is static, the user application

must provide a pointer to space in the user data area into which

the statistics will be copied. This avoids the overhead

associated with dynamic memory allocation in case the user

application calls this routine multiple times.

int cm_get_cm_stats

(

activity_ptr - INPUT

TYPE cm_activity_stats

*activity_ptr

Points to user-allocated data

area of appropriate size. This

routine will copy the activity

statistics into that data area.

It has been implemented in this

fashion to minimize malloc and

free operations, since if is

assumed the user will want this

information more than once.

clientjptr - INPUT

TYPE cm_client_stats

* clientjptr

Points to user-allocated data

area of appropriate size. This

routine will copy the client

statistics into that data area.

It has been implemented in this

fashion to minimize malloc and

free operations, since it is

assumed the user will want this

information more than once.

) RETURNS i status, as identified in cm const .h

IV 18
Common Memory for the PC

2.3.4. Function cm_get_fsm_stats

This function returns the common memory statistics for the

specified user application, as identified in structure

cm_fsm_stats_rec (Appendix C) . Since the size of the statistics

area is static, the user application must provide a pointer to

space in the user data area into which the statistics will be

copied. This avoids the overhead associated with dynamic memory

allocation in case the user application calls this routine

multiple times

int cm_get_fsm_stats

(

fsm

ptr

) RETURNS: status.

- INPUT

TYPE char *fsm

user application name string.

String must be null-terminated

and must be less than or equal to

32 characters in length

(excluding the trailing NULL).

- INPUT

TYPE cm_fsm_stats__rec *ptr

as identified in cm const.

IV 19
Common Memory for the PC

2.3.5. Function cm_get_mbx_stats

This function returns the common memory statistics for the

specified mailbox, as identified in structure cm_mbx_stats_rec

(Appendix C) . Since the size of the statistics area is static,

the user application must provide a pointer to space in the user

data area into which the statistics will be copied. This avoids

the overhead associated with dynamic memory allocation in case

the user application calls this routine multiple times.

int cm_get_mbx_stats

(

mbx

) RETURNS % Status

,

- INPUT

TYPE char *mbx

mailbox name string. String must

be null-terminated and must be

less than or equal to 32

characters in length (excluding

the trailing NULL).

- INPUT

TYPE cm mbx_stats_rec *ptr

identified in cm const.

IV - 20
Common Memory for the PC

3. CONVENIENCE FUNCTIONS

During the development of the PC common memory library, several

utility functions were developed that might be useful to an

application programmer developing a program that uses PC common

memory. These functions provide information or functionality

directly related to PC common memory usage and are documented

below. (Other functions that might be more generally useful are

documented in the source listing of file "sfuncs.c". However,

they are not specific only to the use of PC common memory. The

interested reader is encouraged to examine the "sfuncs.c" file.)

3.1. Function cm_free_update_list

This function frees the memory allocated to an update list. The

update list is passed to the user by function cm_ckmail. It is

the user's responsibility to free the memory allocated to that

linked list. If the user does not free the memory associated

with that linked list, it is conceivable that the application may

run out of dynamically allocable memory and the common memory

manager will be unable to function.

The user may free the blocks of the linked list with calls to the

C function "free" or may use this function.

void cm_free_update_list

(

list - INPUT

TYPE struct update_list *list

This is a pointer to the top of

the update list. The function

will free each block of the

structure, advancing to the next

block, until NULL is reached.

) RETURNS : nothing

IV 21
Common Memory for the PC

3.2. Function cm_get_statusname

This function converts the status code from its numeric

representation into a string containing the corresponding status

mnemonic. The conversion is based on the status codes maintained

in file cm_const.h and listed in Appendix A. All unrecognizable

status code is converted into the string "unknown code"."

char *cm_get_statusname ( code

) RETURNS: pointer to a string containing the status code

associated with the code passed to it. If the

code is not recognizable, the function returns

the string "unknown code"

3.3. Function cm__ini

This function can be used to (1) perform common memory

initialization at a known point in the user application program

and (2) display the version of the common memory object library.

The user application does not have to call this function. Each

common memory interface function, when it is called, checks to

see if common memory has been initialized. If common memory has

not been initialized, the interface function makes a call to

cm_ini. Conversely, if common memory has been initialized, no

call to cm_ini is made.

Function cm__ini is responsible for establishing the data

structures for the use and management of common memory. During

cm_ini execution, the value of global variable CM_DEBUG__LEVEL is

examined. If the value of this variable is greater than zero,

cm_ini will display the common memory object library version

number and will leave the value of CM_DEBUG_LEVEL unchanged. If

it is less than zero, cm_ini sets CM_DEBUG_LEVEL to zero to turn

off common memory debugging statements.

The interested reader is referred to Section IV.

for further

discussions about global common memory variables CM__DEBUG_LEVEL

,

CM GET STATS, and CM VERSION.

void cm_ini (

)

RETURNS : nothing

- INPUT

TYPE int code

This is presumed to be the status

code returned by one of the

common memory interface routines.

IV 22
Common Memory for the PC

4. GLOBAL COMMON MEMORY VARIABLES

The variables listed in the following subsections are declared by

the common memory manager and made available to the user

application program. By manipulating these variables, the

application program can affect the operation of the local common

memory manager. CM_VERSION, as the exception to the previous

statement, has no control function. It is only used to provide

information about the common memory library.

4.1. CM__DEBUG_LEVEL - Control the Amount of Common

Memory Debugging Information Displayed

This variable is declared and initialized in the common memory

object library and is located in file cm_globa.h. It is an

integer variable whose assigned value determines the amount of

diagnostic and/or debugging information the common memory manager

will display at the user console. The debugging levels "build"

upon each other. That is, selecting a debug level also selects

those levels below it (i.e., those with a lower debug level

number are also included). The current CM_DEBUG__LEVEL values and

their effect are:

0

1

2

5

6

7

8

9

no debugging data is displayed.

display the common memory library version. (This

value has been compiled into the object library and

cannot be easily accessed or changed by the user

application program. Section IV. 4.

provides more

information.

)

4 <reserved for future use>

display identifying messages whenever a mailbox is

written or read.

display identifying messages whenever an

application or mailbox entry is added or deleted to

the list maintained by the common memory manager or

whenever a cm_declare fails.

display identifying messages whenever a mailbox

client is added or deleted.

display identifying messages whenever a mailbox

update notification is posted or removed from the

list maintained by the common memory manager,

everything (includes 0-8 and more)

The value of CM_DEBUG_LEVEL is initially set to -1 in file

cm_globa.h. If the application program changes the value to be

greater than or equal to 0 , then the common memory manger will

not change it. Function cm_ini is responsible for initializing

the value of CM__DEBUG_LEVEL to zero if it has a negative value

when common memory is initialized.

IV - 23
Common Memory for the PC

The only time this variable is examined and (potentially) changed

is in function cm_ini. This function is only called once by the

common memory manager although the user application can call it

as frequently as desired. Consequently, the user application can

manipulate the value of CM_DEBUG_VALUE in order to change or halt

the amount of common memory debugging information provided by the

common memory manager.

If the user application intends to manipulate or monitor the

value of CM_DEBUG__LEVEL , it must include the following line in

the application program:

extern int CM DEBUG LEVEL;

4.2. CM_GET__STATS - Control the Acquisition of Common

Memory Statistics

The PC common memory manager includes the capability of gathering

common memory usage statistics. These statistics are available

to any application that has access to the common memory manager.

Gathering these statistics takes CPU time away from the

application process. If the host processor is slow and cannot

provide the level of response necessary for the application, it

may be necessary to analyze where the bottleneck is located. If

it occurs at the interface between the application and common

memory, turning OFF statistics gathering is one way to improve

responsiveness. If it occurs within the user application, then

changing the value associated with CM__GET_STATS will have no

affect.

This variable is declared and initialized in the common memory

object library, in file cm__globa„h, and is of type "boolean".

Its initial value is set to TRUE to enable the gathering of

statistics

If the user application intends to manipulate or monitor the

value of CM_GET_STATS , it must include the following line in the

application program:

extern boolean CM DEBUG LEVEL;

In order to assure the proper definition of structure "boolean",

this line should appear in the user application source code after

the line containing:

INCLUDE "cm types. h"

IV 24
Common Memory for the PC

4.3. CM_VERSION - Determine Version Numbers of the

Common Memory Distribution Components

The PC common memory distribution kit contents are listed in

Section IV. 5.1. Without some sort of tag or label, it becomes a

nearly impossible task to make sure that the components of the

distribution kit are all at the same version number.

No matter how much care is exerted, it is always feasible that

the common memory version of the two INCLUDE files can get out of

synchronization with the version of the common memory object

library or even with each other. Therefore, it is the

application developer's responsibility to verify that

distribution components are at the same version number. If this

verification is not done, unintentional, undesirable and

unexplainable errors may appear during the execution of the

application program. These errors may be a direct result of

differences in constant definitions or data structures that may

have been introduced in subsequent versions of the common memory

distribution.

CM_VERSI ON is defined and initialized in file cm_const.h via:

#define CM_VERSION "1.0a"

However, two logical variables called CM VERSION actually exist:

one that is easily accessible to the application program and one

that is not so easily accessible. It is neither intended nor

desirable for the user application to change the common memory

version identifiers.

To determine and verify that all common memory distribution

components are at the same version, perform the following steps:

(1) Manually inspect the source listings of files cm_const.h and

cm_types.h. Both files will have an indication of their

common memory version number. File cm_const.h will have it

as part of a #DEFINE statement and file cm_types.h will have

it as part of a comment area near the beginning of the file.

Optionally, you can place a "printf" at the beginning of your

program to remind you what the INCLUDE file versions are once

you have verified that both cm_const.h and cm_types.h are at

the same version level. For example:

printf ("file cm_const.h is at version %s\n" ,CM_VERSION)

(2) Display the common memory version number in file cm_funcs.obj

by compiling and linking a (simple) program that sets the

CM_DEBUG_LEVEL equal to an integer value of 1 (or greater)

and then calls function cm_ini. Compare this version number

with the value determined using step (1).

IV - 25
Common Memory for the PC

If the common memory components do not have the same version

number, it will be necessary to locate the (most recent) matching

set of files.

IV - 26
Common Memory for the PC

5. APPLICATION PROGRAM DEVELOPMENT

5.1. The PC Common Memory Distribution Kit

The PC common memory distribution kit consists of this

documentation set and the following files:

cm const.

contains the definition of constants.

cm_types.h - contains the data structure definitions.

cm_funcs.obj - contains the common memory interface

functions. This is distributed in its

object file form in order to minimize the

potential for user-initiated changes that

may later result in inexplicable common

memory behavior and to control the

possible divergence of common memory

interfaces from that identified in this

documentation

sfuncs.obj - contains utilities used by the common

memory library, some of which may be

useful to the application process, too.

It must be included during application

program linking.

5.2. Compiling Programs That Use the Common Memory

Library

Two of the common memory source files must be included during the

user application compilation. They are files cm_types.h and

cm_const.h. File cm_types.h references variables defined in

cm_const.h, so cm_const.h must be included before cm_types.h. For

the C language compiler, the directive is

# include "cm__const .h"

# include "cm_types.h"

If the user application intends to access or manipulate variables

CM_DEBUG_LEVEL or CM_GET_STATS , the respective "extern" statement

should be inserted following the above two lines, as:

extern int CM_DEBUG_LEVEL

extern boolean CM_GET_STATS

File cm_types.h defines all the common memory data structures.

File cm_const.h defines all the status return constants. This

file is necessary if the user application will be testing the

status value returned by each common memory function.

IV 27
Common Memory for the PC

Applications that are written in programming languages other than

C and that cannot import these declarations must provide

equivalent data structures and constant declarations.

5.3. Linking Programs That Use the Common Memory

Library

Two object files must be included in the link process. They are

files cm_funcs.obj and sfuncs.obj.

File cm_funcs.obj contains all the common memory interface

routines

File sfuncs.obj contains some general support utilities required

by the common memory interface routines. They are maintained in

a separate file because they are useful to applications that do

not need to use the common memory library.

IV - 28
Common Memory for the PC

APPENDIX A

STATUS REPORT CODES

FOR THE

COMMON MEMORY INTERFACE FUNCTIONS

The following list identifies the status report codes that the

common memory interface routines can return. They are found in

file CM_CONST.H.

Although each status is associated with a numeric value, it is

strongly recommended that the user application use only the

status name (e.g., I_CM_OK) when testing completion status. It

is conceivable that the values associated with the status may

change in future versions of the common memory interface, whereas

status variable names will not change.

The status values are divided into two groups: informational

(i.e., non-fatal) and fatal. The boundary is established at

variable E_CM_FATALERR . Status values less than E__CM__FATALERR

are informational. Status values greater than or equal to

E_CM_FATALERR report fatal errors.

Informational status values are used to indicate that the call to

the common memory interface function was successfully completed

while concurrently providing some additional information

affecting that call. Fatal status returns are used to indicate

that the call to the common memory interface function was aborted

and the cause of the abort.

CONSTANT

I CM OK

HEX

VALUE DESCRIPTION

0x0 normal success indicator

I CM MBXACTV

i_CM_pupMBX

this application and for similar

access (READ/XREAD or WRITE/XWRITE )

If DECLARE was used to change access

from exclusive to non-exclusive (or

vice-versa), then the change was made.

Additional client entries are not made

in the client list of the respective

mailbox

0x2 mailbox successfully undeclared, but

other applications are still

connected. In the case of cm_disc,

this refers to the status of one or

more mailboxes.

0x4 mailbox was previously declared by

A 1
Common Memory for the PC

CONSTANT

I CM MOREDATA

HEX

VALUE DESCRIPTION

0x5 cm_read was successfully performed.

However the int variable pointed to by

"nr__bytes" was non-zero when the call

was made and specified a number of

bytes that was less than the number of

bytes actually available in the

mailbox. Only the number of bytes

specified in the int variable pointed

to by "nr__bytes" was transferred to

the user data are. More data is

actually available.

Errors greater than Ofx are FATAL errors. This means that the

requested action was NOT performed.

EJUM^FATALERR

E CM INSUFFMEM

0x10 defines the start of FATAL ERROR range

0x10 insufficient memory, malloc failed

E_CM_MBXERR 0x20

E^CM^MSXNOREAD 0x21

E_CM_MBXN0XREAD 0x22

E_CM_MBxNOWR!TE 0x24

E CM MBXNOXWRITE 0x28

base value for mbx errors

can 8 1 have READ - another has XREAD

can’t have XREAD - another fsm has

either READ or XREAD

can't have WRITE - another has XWRITE

can’t have XWRITE - another fsm has

either WRITE or XWRITE

E_CM_MbxS I Z El 0 x29 invalid size, returned if:

(1) negative size in cm_declare, or

(2) byte count < 1 for cm_write, or

(3) size doesn't match previouslydeclared size (for cm_declare), or

( 4 ) attempt to write nr_bytes

greater than declared size

E_CM_MBXACCESS 0x2a invalid mbx access, returned if:

(1) unrecognizable mbx access code

supplied for a cm_declare or

cm_undeclare, or

(2) invalid list_type supplied to

cm__get_fsm__l i s t

A - 2
Common Memory for the PC

CONSTANT

E CM MBXACCBOTH

E_CM_MBXNAME

E CM MBXNOTDECL

E_CM_FSMERR

E_CM_FSMNAME

E CM FSMNOTINCM

HEX

VALUE DESCRIPTION

0x2b can't declare both READ and XREAD or

WHITE and XWHITE in the same mbx

declare. However, you can later

declare a mbx to be READ after having

previously declared it XREAD . . . this

changes your access and lets other

fsm's have access.

0x2c invalid mbx name - too long or none

given

0x2d returned if : (1) fsm attempts to undeclare a mbx

for which it is not a client for

the respective access, or

(2) fsm attempts to perform read or

write actions w/ a mbx for which

it is not a client for the

respective access, or

( 3 ) fsm requests any cm action

without being a client of cm, or

(4) attempt to get info for a mbx

that is not in common memory

0x30 base value for fsm errors

0x31 invalid name - too long or none given

0x32 fsm not a common memory client

A - 3
.

.
Common Memory for the PC

APPENDIX B

COMMON MEMORY MAILBOX ACCESS CODES

The following list identifies the mailbox access codes that the

common memory interface routines will accept. They are found in

file CM CONST. H.

Although each access type is associated with a numeric value, it

is strongly recommended that the user application use only the

access name (e.g., CM_READ_ACCESS ) . It is conceivable that the

values associated with the access names may change in future

versions of the common memory interface, whereas access names

will not change.

HEX

CONSTANT VALUE DESCRIPTION

CM__READ_ACCESS Oxl The declaring application is

requesting shared mailbox read access.

This will be granted as long as no

other application has previously

declared exclusive read access. Other

applications may declare shared read

access for the same mailbox.

CM__XREAD_ACCESS 0x2 The declaring application is

requesting exclusive mailbox read

access. This will be granted as long

as no other application has read or

exclusive read access. Use this

option with caution, since it also

precludes the network from accessing

this mailbox. A future extension will

allow the mailbox declarer to generate

a mailbox access list.

CM__WRITE_ACCESS 0x4 The declaring application is

requesting shared mailbox write

access. This will be granted as long

as no other application has previously

declared exclusive write access.

Other applications may declare shared

write access for the same mailbox.

CM_XWRITE_ACCESS 0x8 The declaring application is

requesting exclusive mailbox write

access. This will be granted as long

as no other application has write or

exclusive write access. Use this

option with caution, since it also

B 1
Common Memory for the PC

precludes the network from accessing

this mbx. A future extension will

allow mbx declarer to generate a mbx

access list.

Mailbox access can be specified by using the appropriate access

constant individually or by specifying the bit-wise OR of two or

more access constants. For example, using the C language syntax,

both READ and WRITE access can be specified via

CM READ ACCESS I CM WRITE ACCESS

The common memory manager checks the validity of the access

request. Any access code combination can be submitted except one

where the user process is requesting both exclusive and nonexclusive access for the same purpose (e.g 0 # READ or WRITE). The

following combinations are illegals

CM_READ_ACCESS | CM__XREAD_ACCESS | <anything else>

CM_WRITE_ACCESS [ CM_XWRITE_ACCESS | <anything @lse>

B 2
Common Memory for the PC

APPENDIX C

DATA STRUCTURES

USED IN THE

COMMON MEMORY INTERFACE FUNCTIONS

The data structures specific to the common memory functions

available to the user application are detailed below. They are a

subset of the complete set of data structures used by the common

memory library. They can be found in file cm_types.h.

In some instances, constants are referenced in the type

definitions. When referenced, they are displayed in uppercase

characters. The values for these constants are found in file

cm const.h.

C.l. STANDARDIZED DEFINITIONS

The following are some standardized definitions used in

subsequent type declarations

typedef unsigned char byte;

typedef long int timestamp; /* nr of seconds since

01 Jan 1970 */

C.2. UPDATE LIST STRUCTURE

When a mailbox is written to, the common memory manager checks to

see if an entry identifying this mailbox already exists on the

update list maintained by each reader client of that mailbox. If

an entry already exists, no further action is taken. If an entry

does not exist, an entry identifying this mailbox is appended to

the update list. The list is maintained in FIFO (first-in-firstout) order.

typedef struct update_list {

int mbxhandle; /* identifies the mbx that has

been changed */

struct update_list *next; /* points to next list entry */

};

C.3. COMMON MEMORY STATISTICS

The following structures show how the common memory manager

returns common memory utilization statistics.

C - 1
Common Memory for the PC

C.3.1. Function Call Statistics

When a user application requests common memory statistics for

this category, the common memory manager places a copy of the

statistics into the user-specified data area. The data area must

be large enough to contain the data or unpredictable and

undesirable side effects may result.

The following structure is used to return usage statistics for

each of the user-callable functions of common memory. Its

primary use is expected to be as a diagnostic tool.

typedef struct {

Char fsm [ CM_MAXFSMNAMELENGTH ]

char mbx [ CM__MAXMBXNAMELENGTH ]

timestamp when;

unsigned int nr_times;

} bas@_stats;

typedef struct {

base_stats success;

base_stats failure;

} group_stats

/* name of fsm */

/* name of mbx */

/* nr times this

service called */

/* for successes */

/* for failures */

typedef struct {

group__stats cm_declare,

cm_undeclare,

cm_write

,

cm_read

,

cm_ckmail,

cm_disc,

cm_get_mbx_list

,

cm_get_fsm_list

cm__get_cm_stats

,

cm_get_fsm__stats

,

cm__get_mbx_stats

} cm_activity_stats

/* id the various */

/* routines */

/* for cm calls */

typedef struct { unsigned int

mbx_ttl , /*

mbx_active, /*

fsm_ttl , /*

fsm active; /*

} cm client stats;

total nr of mbx's declared */

nr of mbx’s currently active */

total nr fsm's declared */

nr fsm's currently active */

C - 2
Common Memory for the PC

C.3.2. Mailbox and Client Lists

Two functions ( cm_get_mbx_list and cm_get_fsm_list ) return a

pointer to a linked list containing the requested information in

one of the arguments of the function call. In this case, it is

the user's responsibility to FREE the linked list after the

list's usefulness has been completed. As mentioned elsewhere

(Section IV. 1.2), UNIX-portable functions MALLOC and FREE are

used within the common memory manager so the user must use

function FREE to release the space allocated for this list.

The following structure is used to return a copy of the mailbox

list to the common memory client:

typedef struct mbx_list_type {

mbxname[CM_MAXMBXNAMELENGTH] ; /* contains name of mbx */

struct mbx_list__type *next; /* next block, or NULL */

};

The following structure is used to return a copy of the common

memory client list to the user application:

typedef struct fsm__list__type {

fsmname [ CM_MAXFSMNAMELENGTH ] ; /* contains name of fsm */

struct fsm_list__type *next; /* next block, or NULL */

};

C.3.3. Mailbox and Client Statistics

When a user application requests common memory statistics for

this category, the common memory manager places a copy of the

statistics into the user-specified data area. The data area must

be large enough to contain the data or unpredictable and

undesirable side effects may result.

The following is returned whenever common memory client

information is requested via function cm_get_fsm_stats

C - 3
Common Memory for the PC

typedef struct {

int nr_read_mbx; /* nr of read mbx declared */

unsigned int nr_reads; /* nr of mbx reads performed */

timestamp read_time; /* time of last read */

char mbx_read [ CM__MAXMBXNAMELENGTH ] ; /* name of last mbx

read, null-terminated */

int nr_write_mbx; /* nr of write mbx declared */

unsigned int nr_writes; /* nr of writes performed */

timestamp write_time; /* time of last write */

char mbx__wr ite [ CM_MAXMBXNAMELENGTH ] ; /* name of last mbx

written, null-terminated */

int nr_updates; /* nr entries on update_list */

}cm__fsm_stats_rec ;

The following is returned whenever mailbox information is

requested via function cm_get_mbx_stats

typedef struct {

int handle; /* mbxhandle for this mbx */

int declaredlength; /* nr bytes declared */

int msglength; /* nr bytes currently stored */

int read_fsms; /* nr of READ subscribers */

unsigned int read_accesses ; /* nr of READ accesses */

timestamp read_time; /* time of last read */

char reader [ CM_MAXFSMNAMELENGTH J ; /* name of last reader

fsm, null-terminated */

int write_fsms; /* nr of WRITE subscribers */

unsigned int write__accesses ; /* nr of WRITE accesses */

timestamp write_time; /* time of last write */

char writer [ CM_MAXFSMNAMELENGTH ] ; /* name of last writer

fsm, null-terminated */

char x reader [CM__MAXFSMNAMELENGTH] ; /* name of exclusive

reader, null-terminated */

char xwriter [CM_MAXFSMNAMELENGTH] ; /* name of exclusive

writer, null-terminated */

} cm_mbx_stats_rec ;

C - 4
Common Memory for the PC

APPENDIX D

SAMPLE PROGRAM

DEMONSTRATING A COMMON MEMORY MAILBOX INTERACTION

BETWEEN

TWO LOGICALLY SEPARATE APPLICATIONS

D . 1 . PURPOSE OF THE PROGRAM

This program serves as a coding example to programmers wishing to

develop a PC common memory application. It incorporates all

available common memory function calls and is heavily commented

in order to document what the program is attempting to do.

The reader is refered to the program listing for further comments

about the program.

D . 2PROGRAM LISTING

The program name is "cm__sampl . c" and begins on the following

page.

D - 1
Common Memory for the PC

/* cm_sampl.c - sample program to show usage of the common memory routines.

Some procedural and explanatory notes are listed below.

1)

When compiling: Two common memory files must be available during the

compile process, cm_types.h and cm_const.h, in order to

bring In the common memory data structure definitions.

These files do not reference any others, so they may

be placed into a library directory. If desired.

File cm const. h must be Included before cm types. h.

2)

When linking: Include files cmfunes.obj and sfuncs.obj In the

I inking process.

************************************

In this sample program, the following is expected to happen:

3)

Since the common memory version of the two INCLUDE files can get out of

sync with the version of the common memory object library. It is a good

Idea to check the respective versions. To avoid cryptic errors, these

version numbers MUST be identical. If they do not match, It will be

necessary to locate the (most recent) matching set of files.

Check the respective versions via the following (demonstrated below):

1) "pr intf" the CMJERSION from the common memory INCLUDE files,

or check the include file's source code manually, and

2) set CM_DEBUG_LEVEL » 1 to generate a "pr intf "from the common memory initialization routine that Is Internal to the (object)

library. The initialization routine is called the very first

time you attempt to perform a DECLARE, UNDECLARE, READ, WRITE,

CKMAIL, or DISCONNECT action. Set CM_DEBUG_LEVEL to zero for

those applications where you don't need to monitor the common memory library version level.

4)

A common memory Interaction occurs between two application processes:

(1) processj declares a mailbox for READ and WRITE access and

writes something into It. (2) processm

2 declares the same mailbox for READ access and checks

if any of its READ mailboxes have been updated. Since it has

only one mailbox, and it was Just declared, no updates have yet

been posted, process 1 does not perform any read function until

D - 2
Common Memory for the PC

after the next time the mailbox is written to. Thus processj

misses the first mailgram. The next time processj writes Into the

mailbox, processj expects to see an update record (since they

are called sequentially from the main program), processj will

return FALSE until it receives its first mailgram. Thereafter

it will always return TRUE.

(3) processj now enters a state where It writes a new mailgram to

the mailbox every deltajlme seconds. If deltajlme seconds

have not elapsed since the last time it was called, processj

will return FALSE. Only after processj has written the

specified nrjimes to the mailbox will it return TRUE.

(4) Since processj Is called Immediately after each call to processj,

processj should display the contents of the newly-written

mailbox (almost) immediately after it was written by processj.

(5) only when both processj and processj return TRUE does the

main program exit the "when" loop.

5) Get and display the list of all applications active in common memory.

6) Get and display the names of all mailboxes currently In common memory.

7) Get and display the list of READ/XREAD clients for mailbox procJ_mbx.

8) Get and display the list of mailboxes declared for READ/XREAD access by processj

9) Get and display the available common memory statistics for an application

that is not In common memory to see the error generated. Use “process 3".

10)

Get and display the available common memory statistics for an application

that is in common memory. Use "process 1".

11)

Get and display the available common memory statistics for a mailbox

that is not in common memory to see the error generated. Use "procjjnbx"

12)

Get and display the available common memory statistics for a mailbox

that is In common memory. Use "proc 1 mbx".

13)

Undeclare the processj mailbox connections by having it call cmjindeclare.

Once all of it's mailboxes are undeclared, the common memory manager will remove It from It's client list. Demonstrate this by displaying the list

of applications still in common memory. Only 1 should be left.

D - 3
Common Memory for the PC

14) Undeclare the process_l mailbox connections by having It call cm disc

Once all of it's mailboxes are undeclared, the common memory manager will remove it from It's client list. Demonstrate this by displaying the list

of applications still in common memory. The common memory client list

should be empty.

15) Retrieve and display the common memory statistics.

V

# i nc I ude <stdlo.h>

# include “cm_const .h"

#include "cm types.

h"

extern Int CM_DEBUG_LEVEL;

enum states {IN IT, NORMAL, SHUTDOWN);

/$ I I ! 1 I I I II I I I I II

' II I I II I II II I I I I

| main \

1 1 1 1 1 1 1 1 1 1 1 1 1 1

1 1 1 1 1 1 1 1 1 1 1 1 1 1

*/

main ()

{ boolean D0NE1 - FALSE;

boolean D0NE2 FALSE;

char *mbxname, *fsmname;

struct mbxj !st_type *mbxjist;

struct fsmj Istjtype *fsm_llst, *tptr;

emjfsm_statsj’ec fsm^stats;

emjnbx= statsj'ec mbx_stats;

cra^actlvity^stats cm^act ivity;

em_el ient^stats crajsTlents;

Int status, nr; enum states p1_state » INIT,

p2_state * INIT;

pr I ntf ("\n\n\t\t \ —— ; \n

“

"\t\t | section corresponding to |\n"

"\t\t \ !\n"

"\t\t \ NOTE # 3 !\n"

“\t\t I |\n"

"\t\t | Display the common memory |\n"

"\t\t S library version numbers for both |\n"

“\t\t | the INCLUDE files and the j\n"

"\t\t j linked object file. |\n"

"\t\t | |\n"

"\t\t

* —" — —— \n") ; /* the first common memory version number comes from the common memory

INCLUDE file, cm_const.h V

pr intf ("\nThe common memory include file is version %s\n“,CM_VERSION);

/* include before cm^types.h */

/* declared In the cm library */

D - 4
Common Memory for the PC

CM_DEBUG_LEVEL = 1;

/* a common memory debug level of '1' means: display the common memory

object library version nr. The version nr will be displayed by function

cmjni (located in file cm_utlls.c, and thus part of the object file

cm_funcs.obJ) the first time a common memory Interface function is

called. This can be forced to occur NOW by Inserting a call to

function cmjni here, in order to perform common memory Initialization

NOW. The CM_DEBUG_LEVEL must be set to 1 (or greater) before you make

the call to cmjni in order to display the version number. */

cm ini ();

pr intf (“\n\n\t\t | |\n"

"\t\t | section corresponding to |\n"

"\t\t | |\n"

"\t\t ! NOTE #4 |\n"

"\t\t |

! \n“

"YtYt | Two processes access a common |\n"

"\t\t | mailbox, transferlng information |\n H

"\t\t | from one to the other. |\n"

"\t\t | |\n"

"\t\t \n") ; while ((I D0NE1) !! (I D0NE2)) { /• continue until both are done */

D0NE1 - process_1(&p1_state);

D0NE2 = process_2(&p2_state);

pr intf ("\n\n\t\t j j\n"

"\t\t S section corresponding to |\n"

"\t\t | |\n“

"\t\t ! NOTE #5 !\n"

"\t\t ! |\n“

"\t\t ! Get and display the list of ALL |\n"

"\t\t | applications participating in J \n"

"\t\t | common memory. |\n"

"\t\t | J \n“

"\t\t

~ —~~ \n") ; pr intf("\n\nmaln: Get and display the list of ALL applications currently"

“\n participating In common memory\n“);

status = cm_get Jsm_l i st ( NULL

, ' ' ,&fsm_l ist,&nr);

If (status >» E_CM_FATALERR) /* was there a fatal error */

pr Intf ( “ma in: FATAL ERROR Xs returned from cm_get JsmJ lst\n",

cm_get_statusname(status));

D - 5
Common Memory for the PC

else

If (fsmjlst) {

prlntfC’maln: following %d applications are active In common memory. . An", nr);

while (fsmjlst) { /* display the application names V

pr Intf ("\t%s\n" ,fsmJ lst->fsmname)

tptr - fsmj ist->next;

free(fsmjlst); /* free the blocks when no longer needed V

fsm list - tptr;

)

)e I se pr intf (“main; no applications active in common memory\n H );

pr intf ("\n\n\t\t

~ —|\n"

"\t\t ! section corresponding to j\n"

“\t\t ! !\n“

"\t\t J NOTE # 6 |\n“

“\t\t ! |\n“

“\t\t ! Get and display the list of ALL |\n“

“\t\t ! mailboxes in common memory. |\n“

“\t\t ! !\n

B

pr intf(“\n\nmaln: Get and display the list of ALL mailboxes In common memory\n“);

status - cm_get_mbx_l 1st (NULL, ",&mbxj Ist,&nr);

If (status > E_CM_FATALERR) /* was there a fatal error */

pr Intf (“main; FATAL ERROR %s returned from cm_get_mbxj ist\n",

cm_get_sta tusname(status));

else

if (mbxjist) (

pr intf ( "ma In : following Xd mailboxes are declared in common memory. . An", nr);

while (mbxjist) { /* display the application names V

pr intf("\t%s\n",mbx_l ist->mbxname);

tptr - mbxj lst->next;

free(mbx_llst); /* free the blocks when no longer needed */

mbx list- tptr;

)

}else pr intf ("main: no mailboxes declared in common memoryXn");

pr intf ("\n\n\t\t \ |\n“

"\t\t j section corresponding to |\n"

"\t\t | !\n“

"\t\t | NOTE #7 |\n“

“\t\t ! |\n"

"\t\t | Get and display the list or |\n"

"\t\t | READ/XREAD clients for mailbox |\n“

"\t\t | 'proc 1 mbx'. !\n"

“\t\t | |\n"

"\t\t — Xn

- );

printf("\n\nmaln: Get and display the list of READ/XREAD clients for mailbox

"\n proc 1 mbx.\n“);

D - 6
Common Memory for the PC

mbxname = "procj jnbx";

status = cm_get_fsm_l 1st (mbxname, 'r' ,&fsm_ 1 1st, &nr);

if (status >= E_CM_FATALERR) /* was there a fatal error */

pr IntfC’main: FATAL ERROR Xs returned from cm_get_fsmj ist\n“,

cm_get_statusname(status));

else

if (fsm_l 1st) {

pr IntfC’main: Xs has following Xd READ/XREAD clients ...\n", mbxname, nr);

while (fsmjist) { /* display the application names */

pr lntf("\tXs\n",fsmJ ist->fsmname);

tptr = fsmj lst->next;

free(fsmjTst); /* free the blocks when no longer needed */

fsm list tptr;

}

}else pr IntfC’main: no READ/XREAD applications declared mailbox Xs\n", mbxname);

pr I ntf ( "\n\n\t\t J — ~

j \n"

"\t\t | section corresponding to i\n"

"\t\t | ! \n"

"\t\t | NOTE #8 |\n"

"\t\t | !\n“

"\t\t | Get and display the list of IXn"

"\t\t | mailboxes declared for READ/ |\n”

“\t\t | XREAD access by 'process r. |\n"

"\t\t | J\n"

“\t\t \n“) ; pr Intf

(

H \n\nmain: Get and display the list of mailboxes declared for READ/XREAD”

"\n by processJ An");

fsmname » "process_1“;

status « cmjjetjnbxJ 1st (fsmname, 'r' ,&mbx_l lst,&nr);

If (status >* E_CM_FATALERR) /* was there a fatal error V

printf("main: FATAL ERROR Xs returned from cm_get_mbx_ I ist\n",

cm_get_statusname(status));

else

If (mbxjist) {

pr lntf("main: Xs has following Xd READ mailboxes ...\n", fsmname, nr);

while (mbxjist) { /* display the application names */

pr intf ("\tXs\n",mbx_l ist->mbxname);

tptr * mbxj ist->next;

free(mbxjTst); /* free the blocks when no longer needed */

mbx list « tptr;

)

}else pr lntf("maln: no READ/XREAD mailboxes declared by Xs\n", fsmname);

D 7
Common Memory for the PC

pr Intf ("\n\n\t\t ! !\n"

"\t\t ! section corresponding to !\n"

M \t\t ! !\n"

“YtYt i NOTE # 9 | \n“

"\t\t | |\n"

"\t\t | Get and display the available |\n"

"\t\t | common memory statistics for an j\n"

“\t\t | application that is not in j\n"

"\t\t ! common memory. Error will be |\n"

"\t\t | generated. Use 'process 3'. |\n“

“\t\t | |\n"

"YtYt

" —~ \n“) ; pr intf("\n\nmain: Get and display the available common memory statistics for”

"\n an application that doesn't exist. Expect an error report. \n M );

fsmname =* “processj";

status = cm_get_fsm_stats(fsmname,&fsmjtats);

if (status >« E_CM_FATALERR) /* was there a fatal error V

pr intf(“main: FATAL ERROR %s returned from cmjjetJsm_stats\n",

emjjet_statusname(status));

else {

printf("\t%d read mbx's\n\t%u reads performed\n\t last one at ",

fsmjtats.nrjeadjnbx,

f smjtats . nr jeads)

pr intf (“%s\tmbx; %s\n\t%d write mbx's\n\t%u writes performed\n\t K

"last one at ",

(fsmjtats.readjime) ? ct ime(&fsmjtats.readjime) s "<none»\n",

fsrajtats.mbxjead,

fsmjtats .nr jir itejnbx,

fsmjtats .nr_wr ! tes)

pr lntf("%s\tmbx: Xs\n\t%d updates on the update llst\n“,

(fsmjtats.wr IteJIme) ? et ime(&fsm_$tats.wr IteJ Ime) : "<none>\n",

f smjtats . mbxjwrlte

fsm stats. nr updates);

}

pr intf("\n\n\t\t i — !\n"

"\t\t I section corresponding to j\n"

"\t\t *

i |\n"

"\t\t | NOTE # 10 !\n"

"\t\t i

i j\n"

"\t\t I Get and display the available j\n"

"\t\t j common memory statistics for |\n"

"\t\t | processj. |\n"

"\t\t i

i |\n"

"\t\t " \n");

pr lntf("\n\nmain: Get and display the available common memory statistics for"

"\n an application that does exist. \n");

fsmname = "processj";

status * cm_get_fsm_stats(fsmname,&fsm_stats);

D - 8
Common Memory for the PC

if (status >= E_CM_FATALERR) /* was there a fatal error V

printf("main: FATAL ERROR Xs returned from cm_get_fsm_stats\n M

, cm_get_statusname(status));

else {

prlntf("\tXd read mbx's\n\tXu reads performed\n\t last one at ",

fsm_stats .nr_read_mbx,

fsm_stats.nr_reads);

pr Intf (“XsXtmbx: XsNnYtXd write mbx's\n\tXu writes performed\n\t"

"last one at ",

(fsm_stats.read_t i me) ? ct lme(&fsm_stats.read_t ime) : "<none>\n",

fsm_stats.mbx_read,

fsm_stats.nr_write_mbx,

fsm_stats.nr_wr ites);

pr Intf ("XsNtmbx: XsNnYtXd updates on the update 1 1 st\n“

(fsm_stats.wr ite_t ime) ? ctime(&fsm_stats.write_time) : "<none>\n",

fsm_stats.mbx_write,

fsm stats. nr updates);

}

pr intf ( \n\n\t\t i ;\n . "\t\t I section corresponding to ! \n"

"\t\t i

i |\n"

"\t\t ! NOTE # 11 |\n"

"\t\t i

i |\n"

"\t\t I Get and display the aval lable |\n"

"\t\t ! common memory statistics for a |\n"

"\t\t I nonexistent mailbox. |\n"

"\t\t i

i |\n"

"\t\t \n “ )

pr Intf ("\n\nmaln: Get and display the available common memory statistics for"

“\n a mailbox that doesn't exist. \n");

mbxname = "proc_3_mbx";

status = cm_get_mbx_stats(mbxnarae,&mbx_stats);

If (status >« E_CM_FATALERR) /* was there a fatal error */

pr intf

( "ma In : FATAL ERROR Xs returned from cm_get_mbx_stats\n",

cm_get_statusname(status) )

else {

pr lntf("\tmbxhandle Xd, declared length Xd, msg length Xd\n\t"

“Xd readers w/ Xu read actions\n\t last by Xs i",

mbx_stats. handle, mbx_stats.declaredlength,mbx_stats.msglength,

mbx_stats . read_f sms , mbx_stats . read_accesses

mbx_stats. reader);

printf(" Xs\tXd writers w/ Xu write actlons\n\t last by Xs §",

(mbx_stats.read_t ime) ? ct ime(&mbx_stats.read_t ime) : "<none>\n",

mbx_stats.wr ite_fsms, mbx_stats.wrlte_accesses,

mbx stats. wr iter);

D - 9
Common Memory for the PC

printf(" %s\txreader: %s\n\txwr iter : %s\n"

(mbx_stats.wr ite_t ime) ? ct lme(&mbx_stats.wr ite_t ime) : “<none>\n"

mbx_stats.xreader,

mbx_stats.xwr iter);

}

pr intf ("\n\n\t\t i — !\n"

"\t\t i section corresponding to !\n"

“\t\t i

i !\n“

"\t\t | NOTE * 12 ! \n"

"\t\t i

i !\n"

"\t\t 1 Get and display the available !\n“

"\t\t ! common memory statistics for j\n“

"\t\t i 'proc 1 mbx'. !\n“

"\t\t i

i |\n"

"\t\t ' \n");

pr intf("\n\nmain: Get and display the available common memory statistics for"

"\n a mailbox that does exist. \n");

mbxname « "procj jnbx";

status - cm_get_mbx_stats(mbxname,&mbx_stats);

if (status >= E_CM_FATALERR) /* was there a fatal error V

pr !ntf("main: FATAL ERROR %s returned from cm_get_mbx_stats\n",

cm_get_st a t us name( status));

else {

pr intf ("\tmbxhandle %d, declared length %d, msg length Xd\n\t"

“Xd readers w/ %u read actlons\n\t last by Xs

mbx_stats . hand I e , mbx_stats . dec I ared I ength , mbx_stats . msg I ength

mbx_stats . read^f sms , mbx_stats . read_accesses

mbx_statSo reader);

prlntf(" XsYtXd writers w/ Xu write actlons\n\t last by Xs

(mbx_stats.read_t ime) ? et ime(&mbx_stats.read_t ime) : "<none>\n",

mbx_statSoWr lte_fsms 8 ibx_stats.wr7te_accesses,

mbx_stats. writer);

printf(" Xs\txreader: Xs\n\txwr iter: Xs\n",

(mbx_stats.wr Ste_t ime) ? ct Ime (&mbx_stats. writ e_t ime) : "<none>\n",

mbx_stats.xreader,

mbx stats. xwrlter);

}

D - 10
Common Memory for the PC

pr intf ("\n\n\t\t i An

“\t\t | section corresponding to |\n -

- \t\t i

i |\n"

- \t\t | NOTE # 13 j\n-

- \t\t i

i An -

- \t\t i Cause process_2 to undeclare all An"

"\t\t I its common memory mailbox An"

- \t\t S connections. Display the list An"

- \t\t | or remaining common memory An"

- \t\t I clients. Only one client should An"

"\t\t | be left. An"

- \t\t i

i An"

- \t\t | Process 2 will use cm undeclare An"

- \t\t { to disconnect from the mailboxes An"

- \t\t i

i An"

"\t\t ’ \n");

pr intf("\n\nmaln: Cause process_2 to undeclare Its common memory mailbox connections. -

- \n Then display the common memory client list. Expect only one cl lent .\n“);

p2_state - SHUTDOWN;

D0NE2 process_2(&p2_state);

status = cm_get_fsm_l7st(NULL, " ,&fsmj ist,&nr);

if (status >« E_CM_FATALERR) /* was there a fatal error */

pr IntfCmain: FATAL ERROR Xs returned from cm_get_fsm_l ist\n",

cm_get_statusname(status));

else

if (fsm l 1st) {

prlntf("maln: following Xd applications are active in common memory. . An -

, nr);

while (f sm_ list) { /* display the application names */

pr intf

(

- \tXs\n",fsmJ lst->fsmname);

tptr fsmj ist->next;

free(fsmjlst); /* free the blocks when no longer needed */

fsm 1 1st - tptr;

}

}else pr intf

( "ma In : no applications active In common memory\n - );

D 11
Common Memory for the PC

pr intf ("\n\n\t\t i *

i |\n"

"\t\t i

i section corresponding to j\n"

"\t\t ii An"

"\t\t i

i NOTE # 14 |\n"

"\t\t i

i An"

“\t\t ii Cause processJ to undeclare all An"

"\t\t i

i its common memory mailbox An"

"\t\t ii connections. Display the list An"

"\t\t i

i or remaining common memory An"

"\t\t i

i clients. Only one client should An"

"\t\t ii be left. An"

"\t\t i

i An"

"\t\t i

i Process 1 will use cm disc to An"

"\t\t i

i disconnect from the mailboxes. An"

"\t\t i

i An"

"\t\t \n");

pr intf ("\n\nmain: Cause process 1 to undeclare its common memory mailbox connections.

"\n Then display the common memory client list. Expect zero clientsAn

p1_state - SHUTDOWN;

DONE 1 * processJ(&p1_state);

status * cmjjetJsmJ 1st (NULL, " ,&fsmj ist,&nr);

If (status E_CM_FATALERR) /* was there a fatal error V

pr intfCmaln: FATAL ERROR 2s returned from cm_getjsmj ist\n“,

cnjgetjtatusname(status) )

else

if (fsmjist) {

pr intf ("ma In: following 2d applications are active In common memory. . An", nr);

while (fsmjist) { /* display the application names V

pr I nt f

( "\t2s\n" , f sm_ 1 1 st->f surname )

tptr » fsmj lst->next;

free(fsmjlst); /* free the blocks when no longer needed V

fsm list- tptr;

}

}else pr lntf("main: no applications active in common memory\n");

pr intf("\n\n\t\t

"\t\t

“\t\t

"\t\t

"\t\t

"\t\t

"\t\t

"\t\t

"\t\t

section corresponding to

NOTE * 15

Retrieve and display the common memory usage statistics.

\n"

\n“

\n"

\n"

\n"

\n"

\n"

\n"

\n");

status * cm_get_cm_stats(&cm_act Ivlty, &cm_cl lents);

If (status >« e”cm~FATALERR)” /* was there a fatal error */

pr Intf ("main: FATAL ERROR 2s returned from cm_get_cm_stats\n",

cnjge^statusnametstatus));

D - 12
Common Memory for the PC

else {

printfC’A total of %u

"A total of %u

cm_cl lents.mbx_

cm_cl ients.fsm_

dmp_base_stats(cm_act

dmp_base_stats(cm_act

dmp_base_stats(cm_act

dmp_base_stat s ( cm_act

dmp_base_st at s ( cm_act

dmp_base_stats(cm_act

dmp_base_stats(cm_act

dmp_base_stats(cm_act

dmp_base_stats(cm_act

dmp_base_stats(cm_act

dmp_base_stats(cm_act

dmp_base_stats(cm_act

dmp_base_stats(cm_act

dmp_base_stats(cm_act

dmp_base_stats(cm_act

dmp_base_stats(cm_act

dmp_base_stats(cm_act

dmp_base_stats(cm_act

dmp_base_stats(cm_act

dmp_base_st ats ( cni_act

dmp_base_stats(cm_act

dmp base stats(cm act

}

mbx's were created. %u still active. \n"

fsm's were clients of cm. %u still active. \n",

ttl, cm_cl ients.mbx_act I ve

ttl, cm_cl lents.fsm_act ive);

vlty.cm_declare.falTure > "cm_declare fai lures");

v I ty . cm_dec I ar e . success

, "cm_dec I are successes " )

vity.cm_undeclare.fai lure,"cm_undeclare fal lures");

v I ty .cm_undec I are . success

, "cm_undec I are successes " )

vity.cm_wr Ite.fal lure,"cm_wr Ite fai lures");

v I ty . cm_wr I te . success

, "cm_wr ! te successes " )

vlty.cm_read.fai lure, "cm_read fai lures");

v I ty . cm_r ead . success

, "cm_read successes " )

vity.cm_ckmai I .fai lure,"cm_ckmal I fal lures");

vity.cm_ckmai I .success, "cm_ckma 1 1 successes");

vity.cm_disc.fai lure, "cm_dlsc fai lures");

v I ty . cm_d I sc . success

, "cm_d I sc successes " )

vity.cm_get_mbx_l lst.fallure,"cm_get_mbx_l 1st fai lures");

vity.cm_get_mbx_l 1st .success, "cm_get_mbx_ 1 1st successes");

vlty.cm_get_fsm_l 1st. fa I lure, "cm_get_fsm_l 1st fai lures");

vlty.cm_get_fsm_l 1st .success, "cm_get_fsm_ 1 1st successes");

v I ty . cm_get_cm_stats .failure, "cm_get_cm_stats fail ures " )

v I ty . cm_get_cm_stats . success

, "cm_get_cm_stats successes " )

vlty.cm_get_fsm_stats.fai lure, "cm_get_fsm_stats fal lures");

v I ty . cm_get_f sm_stats . success

, “cm_get_f sm_stats successes");

vity.cm_get_mbx_stats.fai lure,"cm_get_mbx_stats fai lures");

v I ty . cm_get_mbx_stats . success

, "cra_get_mbx_stats successes " )

/*

**

I I II ! II II II II I I I I

I I I I I I I I I I I I I I I I I dmp_base_stats |

1 1 1 1 1 1 1 1 1 T 1 1 1 1 1 1

1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1

V

int dmp_base_stats(func,msg)

base_stats func;

char *msg;

{

prlntf("Xs: Xu\n\tlast by fsm: Xs\n\tfor mbx: %s\n\tat: %s\n",

msg,func.nr_t imes,

(func. fsm) ? func. fsm : " ",

(func. mbx) ? func. mbx : "

(func. when) ? ct lme(&func.when) : "\n");

D 13
Common Memory for the PC

This process initializes itself the first time it is called.

Next, It writes into a mailbox, records the time of write,

and decrements the number of times that it is supposed to

write into the mailbox. If the result Is zero, it

returns TRUE, else It returns FALSE.

The next time It is called. It checks if de I ta_t I me has

elapsed. If not. It returns FALSE. If so, It once again

writes into the mailbox, records the time of the write,

decrements the counter, and returns either TRUE or FALSE

according to the algorithm described before.

At shutdown, the mailboxes are disconnected via cm disc.

*/

boolean processJ (state)

enum states *state;

{ char data[200];

int mbxslze, mbxaccess*,

timestamp timejiow;

struct updateJ 1st ‘update_ptr, *tptr;

int nrbytes, status;

i M 1

1 1 1 1

1 1 1 1 1

1 1 1 1 1

1

1

processj

1 1 1 1 1 1 1 1 1

1 1 1 1 1 1 1 1 1

static timestamp !a$t_wr!te,

deltajime = 10;

static int nr_wrltes * 5;

static Int mbxhandle;

static char *fsm « "processj";

static char ‘mbxname - "procj jnbx";

switch (‘state) { case INIT :•state - NORMAL;

t ime(&last_wr ite);

last_wrlte — 10;

mbxslze « 150;

mbxaccess » CM READ ACCESS

/* timestamp for last cm_write •/

/* nr seconds between cmjrite */

/* total nr of writes to perform */

/* for next call */

/* fake a last_wr Ite time */

/* take off 10 seconds */

CM_WRITE_ACCESS;

status * cm deciare(fsm, mbxname, mbxslze, mbxaccess, Smbxhandle);

if (status >- E_CM_FATALERR)

printf (“processJ : FATAL ERROR %s returned from cm_declare\n",

cm_get_statusname(status) )

break;

D 14
Common Memory for the PC

case NORMAL : t ime(&time_now);

if ((time_now - last_write) >= de I ta_t i me) {

last_write = time_now;

spr intf(data,"processJ wrote mbx (%d writes remaining) on %s

M

, nr_writes-1, ct lme(&time_now));

nrbytes = str len(data);

status = cm write(fsm, &mbxhandle, data, &nrbytes);

If (status >«= E_CM_FATALERR)

pr Intf (“processj : FATAL ERROR Xs returned from cm_write\n H

, cm_get_statusname(status));

return ((—nr_writes) « 0);

}else return(FALSE); /* Insufficient time elapsed */

break; case SHUTDOWN : status * cm disc(fsm);

if (status >- E_CM_FATALERR) {

pr lntf(

B process_l : FATAL ERROR Xs returned from cm_disc\n“,

cm_get_statusname(status));

return (TRUE); /* give MAIN the option for clean getaway */

)

break;

)

}

/* !!!!!!!!!!!!!!! This process Initializes Itself the first time It is called,

i process_2 i Next, and every time it is called thereafter, it checks its

i ! ! ! i ! ! i i ! i ! i !

mail to see If any of the mailboxes that it has declared as READ or XREAD access have been updated. If none. It returns

a boolean value indicating whether It has read any of its

declared mailboxes since they were declared. If updated

mailboxes exist, they are sequentially displayed, the

update list freed, and a boolean value is (set and) returned

to Indicate that a mailbox has been read.

At shutdown, the mailboxes are disconnected via cm undeclare.

V

boolean process_2(state)

enum states ‘state;

{ char data[200];

int mbxsize, mbxaccess;

timestamp time_now;

struct updatejist *update_ptr, *tptr;

Int nrbytes, nr updates, status;

D 15
Common Memory for the PC

static boolean read_one = FALSE;

static int mbxhandle;

static char *fsm = "process_2 u

; static char ‘mbxname = ”proc 1 mbx";

switch (*state) { case INIT :mbxslze = 150;

mbxaccess « CM_READ_ACCESS;

status - cm declare(fsm, mbxname, mbxslze, mbxaccess, &mbxhandle);

if (status >= E_CM_FATALERR) {

pr intf("process_2: FATAL ERROR %s returned from cmjJeelareXn",

cm_get_statusname(status>);

return (TRUE);

}

‘state = NORMAL;

break; case NORMAL :status * cm ckmai l(fsm,&update ptr,&nr updates);

if (status >» E_CMJATALERR) f

prlntf ("processes FATAL ERROR %s returned from cm_ckmai l\n",

cm_getjstatusname(status))

return (TRUE); /* try to give MAIN a graceful exit */

}

if (update=ptr) { /* read updated mailboxes */

read^one - TRUE; /* remember that you read at least one V

tptr ® update_ptr; /* remember start of list for later FREE */

time(&t imejiow);

pr intf("\nprocess_2: it Is now %s",ct ime(&t !me_now));

pr Intf ( "processor %d mailbox update not If Icat ions\n",nr_updates);

while (updatej>tr) {

nrbytes * 0; /* to Insure we get all of the ma 1

1 gram V

status » cm read(fsm, Supdate ptr->rabxhandle, data, &nrbytes);

If (status >« EJMJATALERR) {

pr lntf("process_2: FATAL ERROR %s returned from cm_read\n",

cm get statusname(status));

exit();

}

data[nrbytes] - 0; /* trailing NULL so we can treat as string w/ printf * pr intf("\tmbxhandle: %d, msg is %d bytes long\n"

"\tstatus returned is %s, or %x (hex)\n\tCONTENTS : %s",

update_pt r->mbxhand I e .nrbytes , cm_get_statusname(status) , status , data )

update_ptr » update_ptr->next;

}

cmjree_updatej ist(tptr); /* FREE the update list V

return (readjme);

break;

D 16
Common Memory for the PC

case SHUTDOWN : mbxaccess = CM_READ_ACCESS;

status * cm undeclare(fsm, mbxaccess, &mbxhandle);

if (status >= E_CM_FATALERR ) {

pr intf(“processJ : FATAL ERROR %s returned from cm_undeclare\n“

cm_get_statusname(status));

return (TRUE); /* give MAIN the option for clean getaway */

)break;

}

return (read one);

}

D 17
Common Memory for the PC

D.3. SAMPLE PROGRAM OUTPUT

The output generated by the sample program is shown below. The

correlation between sections of the output and notations made in

the program listing are clearly identified by in-line comments.

In some cases , the sample program generates a line that is wider

than can be represented on these typewriten pages . In these

cases, the line is broken into two parts and the information is

displayed on two sequential lines.

The output begins on the following page.

D 18
Common Memory for the PC

section corresponding to

NOTE # 3

Display the common memory

library version numbers for both

the INCLUDE files and the

I inked object file.

The common memory include file Is version 1.0a

cm Ini: using common memory library version 1.0a

section corresponding to

NOTE # 4

Two processes access a common

mailbox, transfering Information

from one to the other.

process_2: it is now Sat Feb 27 19:50:55 1988

process_2: 1 mailbox update notifications

mbxhandle: 1, msg Is 69 bytes long

status returned is l_CM_0K, or 0 (hex)

CONTENTS: process 1 wrote mbx (4 writes remaining)

on Sat Feb 27 19:50:55 1988

process_2: It is now Sat Feb 27 19:51:05 1988

process_2: 1 mailbox update notifications

mbxhandle: 1, msg Is 69 bytes long

status returned is l_CM_0K, or 0 (hex)

CONTENTS: process 1 wrote mbx (3 writes remaining)

on Sat Feb 27 19:51:05 1988

D 19
Common Memory for the PC

process_2: It is now Sat Feb 27 19:51:15 1988

process_2: 1 mailbox update notifications

mbxhandle: 1, msg is 69 bytes long

status returned is I _CM_0K , or 0 (hex)

CONTENTS: process 1 wrote mbx (2 writes remaining)

on Sat Feb 27 19:51:15 1988

process_2: It is now Sat Feb 27 19:51:25 1988

process_2: 1 mailbox update notifications

mbxhandle: 1, msg is 69 bytes long

status returned is l_CM_0K, or 0 (hex)

CONTENTS: process 1 wrote mbx (1 writes remaining)

on Sat Feb 27 19:51:25 1988

process_2: it is now Sat Feb 27 19:51:35 1988

process_2: 1 mailbox update notifications

mbxhandle: 1, msg is 69 bytes long

status returned is l_CM_0K, or 0 (hex)

CONTENTS: process 1 wrote mbx (0 writes remaining)

on Sat Feb 27 19:51:35 1988

\ section corresponding to !«

I8

\ NOTE # 5

! Get and display the list of ALL

i applications participating In

\ common memory.

i

8

8

8

8

8

I

8

8

B

main: Get and display the list of ALL applications currently

participating in common memory

main: following 2 applications are active In common memory...

processj

process 2

section corresponding to

NOTE # 6

Get and display the list of ALL

mailboxes in common memory.

D - 20
Common Memory for the PC

main: Get and display the list of ALL mailboxes in common memory

main: following 1 mailboxes are declared In common memory...

proc 1 mbx

section corresponding to

NOTE # 7

Get and display the I ist or READ/XREAD clients for mailbox

'proc 1 mbx'.

main: Get and display the list of READ/XREAD clients for mailbox

procj jnbx.

main: procjjnbx has following 2 READ/XREAD clients ... processj

process 2

section corresponding to

NOTE » 8

Get and display the list of

mailboxes declared for READ/

XREAD access by 'process 1'.

main: Get and display the list of mailboxes declared for

READ/XREAD by processj

main: processj has following 1 READ mailboxes ... proc 1 mbx

D - 21
Common Memory for the PC

section corresponding to

NOTE # 9

Get and display the available

common memory statistics for an

appl Icat ion that Is not in common memory. Error will be

generated. Use 'process 3'.

main: Get and display the available common memory statistics for an application that doesn't exist. Expect an error report,

main: FATAL ERROR E_CM_FSMNOTINCM returned from cm_get_fsm_stats

I section corresponding to

l NOTE # 10

\ Get and display the available

\ common memory statistics for

\ process 1.

main: Get and display the available common memory statistics for

an application that does exist.

1 read mbx's

0 reads performed

last one at <none>

mbx: <none>

1 write mbx's

5 writes performed

last one at Sat Feb 27 19:51:35 1988

mbx: procjjnbx

1 updates on the update list

D 22
Common Memory for the PC

section corresponding to

NOTE # 11

Get and display the available

common memory statistics for a nonexistent mai I box.

main: Get and display the available common memory statistics for

a mailbox that doesn't exist.

main: FATAL ERROR E_CM_MBXNOTDECL returned from cm_get_mbx_stats

section corresponding to

NOTE « 12

Get and display the available

common memory statistics for

'proc 1 mbx'

main: Get and display the available common memory statistics for

a mailbox that does exist,

mbxhandle 1, declared length 150, msg length 69

2 readers w/ 5 read actions

last by process_2 e Sat Feb 27 19:51:35 1988

1 writers w/ 5 write actions

last by processj § Sat Feb 27 19:51:35 1988

xreader: <none>

xwrlter: <none>

D - 23
Common Memory for the PC

section corresponding to

NOTE # 13

Cause process_2 to undeclare all

Its common memory mailbox

connections. Display the list or remaining common memory

clients. Only one client should

be left.

Process_2 will use cmjjndeclare

to disconnect from the mailboxes

main: Cause process_2 to undeclare Its common memory mailbox

connections. Then display the common memory client list.

Expect only one cl lent.

main: following 1 applications are active in common memory...

process 1

section corresponding to

NOTE # 14

Cause processJ to undeclare all

Its common memory mailbox

connections. Display the list or remaining common memory

clients. Only one client should

be left.

ProcessJ will use cm_d!sc to

disconnect from the mailboxes.

main: Cause processj to undeclare Its common memory mailbox

connections. Then display the common memory client list.

Expect zero cl lents.

main: no applications active in common memory

D - 24
Common Memory for the PC

section corresponding to

NOTE # 15

Retrieve and display the common memory usage statistics.

A total of 1 mbx's were created. 0 still active.

A total of 2 f sin's were clients of cm. 0 st i 1 1 act ive.

cmjjeclare fal lures: 0

last by fsm:

for mbx:

at:

cm_declare successes: 2

last by fsm: process_2

for mbx: proc 1 mbx

at: Sat Feb 27 19:50:55 1988

cm_undeclare failures: 0

last by fsm:

for mbx:

at:

cm_undeclare successes: 1 last by fsm: process_2

for mbx: proc 1 mbx

at: Sat Feb 27 ?9:51:35 1988

cm_wrlte fal lures: 0

last by fsm:

for mbx:

at:

cm_wr!te successes: 5

last by fsm: processj

for mbx: proc 1 mbx

at: Sat Feb 27 19:51:35 1988

cm_read failures: 0

last by fsm:

for mbx:

at:

D 25
Common Memory for the PC

cm_read successes: 5

last by fsm: process_2

for mbx: proc 1 mbx

at: Sat Feb 27 19:51:35 1988

cm_ckmal I fa I lures: 0

last by fsm:

for mbx:

at:

cmjjkma 1 1 successes: 9002

last by fsm: process_2

for mbx:

at: Sat Feb 27 19:51:35 1988

cmjjlsc fa I lures: 0

last by fsm:

for mbx:

at:

cmjlisc successes: 1 last by fsm: process

for mbx:

at: Sat Feb 27 19:51:36 1988

cm getjnbxJ 1st failures: 0

last by fsm:

for mbx:

at:

cmjjetjnbxJ 1st successes: 2

last by fsm: process

for mbx:

at: Sat Feb 27 19:51:35 1988

cmjjet_fsmJ 1st failures: 0

last by fsm:

for mbx:

at:

cm_get_fsm_l 1st successes: 3

last by fsm:

for mbx:

at: Sat Feb 27 19:51:35 1988

cmj3 et_c m_stats failures: 0

last by fsm:

for mbx:

at:

D 26
Common Memory for the PC

cm_get_cm_stats successes: 0

last by fsm:

for mbx:

at:

cm_get_fsin _stat s failures: 1 last by fsm: process_3

for mbx:

at: Sat Feb 27 19:51:35 1988

cm_get_fsm_stats successes: 1 last by fsm: process

for mbx:

at: Sat Feb 27 19:51:35 1988

cmjjet_mbx_stats failures: 1 last by fsm: proc_3_mbx

for mbx:

at: Sat Feb 27 19:51:35 1988

cm_getjnbx_stats successes: 1 last by fsm:

for mbx: proc 1 mbx

at: Sat Feb 27 19:51:35 1988

D - 27
'
Common Memory for the PC

APPENDIX E

SOURCE CODE LISTINGS OF THE COMMON MEMORY PROGRAMS

The source code listings of the individual program files

comprising the PC common memory have been placed at this appendix

in the order shown below.

E.l. CM CONST.

E.2. CM GLOBALS.H

E.3. CM TYPES.

E.4. CM FUNCS.C

E.5. CM UTILS.

E.6. SFUNCS .

Their pages are formatted and numbered differently from the rest

of this document in order to provide a reference base for

discussions of content.

E 1
-

V
FL I ST (VI . 1 /FR) CM

Listed: 26-AUG- 1988 16:41:08

1 /* cm_const.h - Contains all1 constant definitions V

3 #def ine CM VERSION "1.0a" /* chg here and in cm types. h */

4 #def ine MAXMBXNAMELENGTH 32

5 #def Ine MAXFSMNAMELENGTH 32

6 #def ine CM MAXMBXNAMELENGTH MAXMBXNAMELENGTH + 1 /* spc for trail ing nulV

7 #def ine cm'maxfsmnamelength MAXFSMNAMELENGTH + 1 /* spc for trail ing nulV

9 # i fndef TRUE

10 #def Ine TRUE 1

11 #define FALSE 0

12 #endlf

15 /* mbx access constants. Combinations are achieved by OR ing the values.

16 For example, for both READ and WRITE access, the call to the appropriate

17 CM routine would have CM READ ACCESS ! CM WRITE ACCESS */

18 #def ine CM READ ACCESS 0x1 /* shared read access V

19 #def ine Cm"xREAD_ACCESS 0x2 /* exclusive read access. Use

20 w/ caution, since It also

21 precludes the network from

22 accessing this mbx. So,

23 what's the value?? Future

24 extension will allow declarer to

25 generate a mbx access list V

26 #def ine CM WRITE ACCESS 0x4 /* shared write access V

27 #deflne CM~XWR ITE_ACCESS 0x8 /* exclusive write access */

29 /* status returns

30 0x00 - OxOF - normal returns. This means that the requested action

31 was performed. V

32 #def ine 1 CM OK 0x0 /* normal success Indicator */

33 #def ine l~CM~MBXACTV 0x2 /* mbx successfully undeclared, but

34 other fsm's still connected. In the

35 case of cm_disc, this refers to the

36 status of one or more mbx's. */

37 tdefine l_CM_DUPMBX 0x4 /* mbx was previously declared by this

38 fsm, and for similar access (READ/XREAD

39 or WRITE/XWRITE). If DECLARE was used to

40 change acces from exclusive to non-exclusive

41 (or vice-versa), then change was made.

42 Additional entries are not made in the

43 client list of the respective mailbox. V

44 #def ine l_CM_MOREDATA 0x5 /* cm_read was successfully performed.

45 However the int variable pointed to by

46

u nr_bytes" was non-zero when the cal 1 47 was made, and specified a number of bytes

48 that was less than the number of bytes

49 actual ly aval lable in the mai Ibox. Only

50 the number of bytes specified in the int

51 variable pointed to by "nr bytes" was

CONST .

PAGE 1
FL I ST ( VI . 1 /FR) CM

Listed: 26-AUG-1988 16:41:08

52

53

transferred to the user data are. data Is actually available. */

More

55 /* Errors greater than OFx are FATAL errors. This means that the requested

56 action was NOT performed. */

59 /* 0x10 - OxlF = general errors (or errors common to multiple categories */

60 #def ine E CM FATALERR 0x10 /* defines the start of FATAL ERROR range */

61 ^define E“CMJNSUFFMEM 0x10 /* insufficient memory, mal loc failed */

64 /* 0x20 - 0x2F mbx errors */

65 #def ine E_CM_MBXERR 0x20 /* base value for mbx errors */

66 7® the foi lowing 4 error codes must always be related according to */

67 /* <err code> * E CM MBXERR + CM <type> ACCESS */

68 #def ine E CM MBXNOREAD

” 0x21 /* can't have READ - another has XREAD */

69 #define E~CM”mBXNOXREAD 0x22 /* can't have XREAD - another fsm has

70 either READ or XREAD */

71 #def ine E CM MBXNOWRITE 0x24 /* can't have WRITE - another has XWRITE V

72 #def ine E~CM~MBXNOXWRITE 0x28 /* can't have XWRITE - another fsm has

73 either WRITE or XWRITE */

74 #def ine E_CM_MBX$IZE 0x29 /* invalid size, returned if:

75 (1) negative size In cm_declare, or

76 (2) byte court < 1 for cm_write, or

77 (3) size doesn't match previously78 declared size (for cmjdecl are), or

79 (4) attempt to write nrgbytes

80 greater than declared size */

81 ^define EJNJBXACCESS 0x2a /* invalid mbx access, returned if:

82 (1) unrecognizable mbx access code

83 supplied for a cm_declare or

84 em_undec!are, or

85 (2) Invalid list=

type supplied to

86 cmjjetjsmjlst */

87 idefine E_CM_MBXACCBOTH 0x2b /* can't declare both READ and XREAD or

88 WRITE and XWRITE in the same mbx declare.

89 However, you can later declare a mbx

90 to be READ after having previously

91 declared it XREAD ... this changes your

92 access and lets other fsm's have

93 access. */

94 itdefine E CM MBXNAME 0x2c /* invalid mbx name - too long or none given

95 #def Ine E~CM~MBXNOTDECL 0x2d /* returned if : 96 (1) fsm attempts to undeclare a mbx

97 for which it is not a client for

98 the respective access, or

99 (2) fsm attempts to perform read or

100

101

102

write actions w/ a mbx for which

it is not a client for the

respective access, or

CONST .

PAGE 2
FLIST (VI . 1/FR)

Listed: 26-AUG- 1 988

103

104

105

106

108 /* 0x30 - 0x3F - fsm

109 #deflne E CM FSMERR

110 #deflne E'CMFSMNAME

111 ttdefine e”cm"fSMNOTINCM

16:41 : 08

CM

(3) fsm requests any cm action

without being a client of cm, or

(4) attempt to get info for a mbx

that is not in common memory */

errors V

0x30 /* base value for fsm errors V

0x31 /* invalid name - too long or none given V

0x32 /* fsm not a common memory client V

CONST .

PAGE 3
.

„
FL I ST (VI . 1 /FR) CM

Listed: 26-AUG- 1988 16:41:14

1 /* cm_globals.h - contains al I global variable declarations V

3 # include <stdio.h>

4 # include "cm_const.h“ /*

5 # include

H cm_types.h"

7 int cmjnbxhandie = 0; /*

9 fsm_rec *cm_fsmjlst = NULL; /*

10 mbx rec *cm mbx list = NULL; /*

include cm_const.h before cm_types.h V

used by CMM in assigning mbxhandles */

list of active fsm's maintained by CMM */

list of declared mbx's maintained by CMM V

/* The following are Initialized In function cmjni found In cm_utlls.h.

The first 2 are EXTERN so they can be adjusted by the user application pgm.

For testing and development purposes, they are currently initialized In routine cm ini . */

13

14

15

16

18 Int CM DEBUG LEVEL - -1;

19 boolean CM_GET_STATS - TRUE;

20 cm_activity_stats *cm_activity - NULL;

21 cm client stats *cm clients » NULL;

/* causes debugging statments to be displayed

/* tel Is cmm to gather some performance stats

/* tracks useage of cm routines V

/* keeps comt of mbx's and fsm's */

GLOBALS .

PAGE 1

/

/
.
FLIST (VI . 1/FR) CM

Listed: 26-AUG- 1 988 16:41:15

1 /* cm_types.h - definitions of types used in the common memory and

2 interface routines.

4 The source program that includes this fl le must also

5 include file

,, cm_const.h“.

7

1 1 1 1 1 1 1 1 1 1 M i M i m 1 1 1 1 1 1 1 m i

1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1

8

9

!

1 Ibrary version 1.0a i <—

1 1 1 1 1 1 1 1 1 M M 1 1 1 1 1 1 1 1 1 1 M 1 1

1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1

chg here and In cm_const.h

11 */

12 # i fndef boolean

13 typedef int boolean;

14 #end!f

18 /* some standardized definitions */

19 typedef msigned char byte;

20 typedef long Int timestamp; /* nr of seconds since 01 Jan '70 */

24 /* this Is how mailbox variables are stored */

25 typedef struct mbx_stats {

26 Int nrjsms; /* nr of subscribers to this mbx */

27 unsigned Int nr_accesses; /* nr of times mbx accessed */

28 timestamp when; /* time of last access */

29 struct fsm rec type *who; /* pts to last accessing fsm */

30 };

31 typedef struct client_chain {

32 struct fsm_rec_type ‘who; /* ptr to subscribing fsm record */

33 boolean exclusive; /* TRUE if fsm has XREAD or XWRITE */

34 struct client chain *next; /* ptr to next fsm or NULL */

35 };

36 typedef struct mbx rec type {

*

37 char mbxname [CM_MAXMBXNAMELENGTH]

38 Int handle; /* short (nimeric) name for mbx */

39 Int declared length; /* nr bytes declared */

40 int msglength; /* nr bytes current ly stored */

41 byte *data; /* ptr to actual data area */

42 struct mbx_stats readers; /* reader statistics */

43 struct mbx_stats writers; /* writer statistics */

44 struct cllent_chain ‘reader list; /* 1 inked list of fsm_rec ptrs */

45 struct client_chain ‘writer list; /* 1 Inked list of fsm_rec ptrs */

46 struct mbx_rec_type ‘next; /* ptr to next mbx list entry */

47 }mbx_rec;

49 /‘this is how fsm variables are stored */

50 typedef struct mbx_decl_chain { 51 struct mbx rec type *mbx; /* ptr to subscribed mbx record */

TYPES.

PAGE 1
FL I ST (VI . 1 /FR)

Listed: 26-AUG- 1988 16:41:15

CM__TYPES . H

PAGE 2

52 struct mbx dec 1 chain ‘next; /* ptr to next mbx or NULL */

53 };

54 typedef struct fsm_stats {

55 int nrjnbxes; /* nr of mbxes declared for "this" access */

56 unsigned int nr_accesses; /* ttl nr of accesses */

57 timestamp when; /* time of last access */

58 int mbxhandle; /* last mbx accessed */

59 struct mbx dec! chain *mbx list; /* chain of declared mailboxes for "’this" access */

60 };

61 typedef struct updateJ ist {

62 int mbxhandle; /* id's mbx that has been changed */

63 struct update list ‘next; /* pts to next i Ist entry */

64 };

65 typedef struct fsm rec type {

66 char fsmname[CM~MAXFSMNAMELENGTH3 ; /* name, null terminated */

67 struct fsm^stats read; /* READ stats */

68 struct fsm^stats write; /* WRITE stats V

69 struct update^ 1 Ist ‘update^top; /‘FIFO list of subscribed READ mbxes

70 that have been updated. CMM wi 1 1 FREE them after fsm reads

71 the mbxes. Or, fsm can be handed this I ist w/ CM SYNC call

72 and fsm must FREE the i ist when done. If a subsequent update

73 is made to a mbx that is already on the ! 1st 9 no additional

74 list entry wilt be submitted. V

75 struct updateJ ist *update_bot; /* position of the update list where

76 new entries are made to maintain

77 the FIFO order. */

78 int nrjjpdates; /* nr of ipdate entries on the ! Ist J

79 struct fsm_rec_type *next; /* ptr to next fsm record or NULL V

80 } fsmjec;

84 /‘this Is how the cmm stores statistics */

85 typedef struct {

86 char fsm[CM MAXFSMNAMELENGTH]

/* name of fsm */

87 char mbX[CM~MAXMBXNAMELENGTH]

/* name of mbx, if appropriate */

88 timestamp when;

89 unsigned int nr_tlmes; /* nr times this service called */

90 ) base_stats;

92 typedef struct {

93 base^stats success; /* for when the call succeeded */

94 base_stats failure; /* for when It failed V

95 } group^stats;

97 typedef struct {

98 group_stats cmjjeclare.

99 cnujndeclare.

100 cm_write.

101 cmjead.

102 cm ckma i 1
FL I ST (VI . 1 /FR) CM

Listed: 26-AUG- 1988 16:41:15

103 cmjjisc,

104 cm_get_mbx_l ist,

105 an_get_fsfnj ist,

106 an_get_cmj5tats,

107 cm_get_fsm_stats.

108 cm_get_mbx_stats;

109 } cm_activlty_stats; /* stats for an calls */

111 typedef struct {

112 unsigned Int mbx_ttl. /* ttl nr mbx's declared */

113 mbx_actlve. /* nr mbx's currently active */

114 fsm_tt 1

/* ttl nr fsm's declared */

115 fsm_active; /* nr fsm's currently active */

116 } cm_cl ient_stats;

120 /* the following structure Is used to return a copy of the mbx list to the cm cl1 lent */

121 typedef struct mbx list type {

122 mbxname [CM_MAXMBXNAMELENGTH ]

/* contains name of mbx */

123 struct mbx list type ‘next; /* pts to next, or is NULL at end */

124 };

125 /* the following structure Is used to return a copy of the fsm 1 Ist to the cm cli lent */

126 typedef struct fsm 1 ist type {

127 fsmname[CM_MAXFSMNAMELENGTH]

/* contains name of fsm */

128 struct fsm list type ‘next; /* pts to next, or Is NULL at end */

129

132 /* the fol lowing is returned tfienever fsm information is requested via

133 cm get fsm stats

134 */

135 typedef struct {

136 int nr_read_mbx; /* nr of read mbx declared */

137 unsigned Int nr_reads; /* nr of mbx reads performed */

138 timestamp read time; /* time of last read »/

139 char ntox_read[5il_MAXMBXNAMELENGTH]

/* name of last mbx read, nul 1 -terminated*/

140 int nr_wr ite_mbx; /* nr of write mbx declared */

141 unsigned Int nr_wrltes; /* nr of writes performed */

142 timestamp write time; /* time of last write */

143 char mbx_wrlte[CM_MAXMBXNAMELENGTH]; /• name of last mbx written, null-terminated

144 Int nr_ipdates; /* nr updates waiting in the updatejlst */

145 }cm_fsm_stats_rec;

147 /* the following is returned whenever mbx Information Is requested via

148 cm get mbx stats

149 */

150 typedef struct { 151 int handle; /* short (numeric) name for mbx */

152 int declared length; /* nr bytes declared */

153 int msg length; /* nr bytes currently stored */

TYPES.

PAGE 3
FLIST (VI . 1/FR) CM

Listed: 26-AUG- 1 988 16:41:15

154 int read_fsms; /* nr of READ subscribers */

155 ms i gned Int read_accesses

/* nr of READ accesses */

156 timestamp read time; /* time of last read V

157 char reader[CM~MAXFSMNAMELENGTH]

/* name of last reader fsm V

158 int write_fsms; /* nr of WRITE subscribers V

159 uns i gned int wr i te_accesses

/* nr of WRITE accesses V

160 timestamp write time; /* time of last write V

161 char writer [CM MAXFSMNAMELENGTH]; /* name of last writer fsm V

162 char xreader[CM MAXFSMNAMELENGTH]; /* name of xreader fsm */

163 char xwr iter[CM~MAXFSMNAMELENGTH]

/* name of xwr iter fsm V

164 }cm mbx stats rec;

TYPES.

PAGE 4
FLIST (VI . 1/FR) CM

Listed: 26—AUG— 1 988 16:55:39

1 /* cm_funcs. c - contains the common memory interface routines

2 used by cl lent processes.

5 The following section describes the purpose of each interface function.

6 The argument list for each function Is described in detail. Each

7 f met ion returns an integer status value that correlates with what the

8 fmet ion is to perform (hence the 'int' before each function name).

10 The list of all potential status values that this family of functions

11 can return, and their significance, is provided in file cm const.

14

15

16

17

18

19

20

2122

23

24

25

26

27

28

29

30

3132

33

34

35

36

37

38

39

40

41

int cm_declare(fsm - INPUT TYPE char *fsm

fsm name string. String must

be null-terminated, and must be <» 32

characters in length (excluding NULL),

mbxname - INPUT TYPE char *mbxname

mbx name string. String must

be nul I -terminated, and must be <* 32

characters in length (excluding NULL),

mbxsize - INPUT

TYPE int mbxsize max size of mbx to be created,

mbxaccess - INPUT TYPE Int mbxaccess

can be READ {WRITE ! XREAD | XWRITE,

but not both of the same kind in the same

declaration. The associated constants are

listed In cm_const.h.

mbxhandle - OUTPUT

TYPE Int ‘mbxhandle

Value returned In the int variable Is to be

used as a shorthand reference for mbx for

calls to all other cm routines.

) PURPOSE: Routine creates the necessary fsm, mbx, and mbx client

structures within common memory to support future mailbox

manipulations by the declaring fsm.

43 NOTE: When you cm_declare to an existing mbx for READ or XREAD,

44 the emm will NOT place an entry into your "update list" for

45 that mbx. The purpose of the update list is to Indicate that

46 the mbx contents have been written SINCE the time of your

47 cm_declare or cm_read. It Is assumed that you will perform an

48 initial cm_read as a matter of course (If desired).

50 RETURNS: status, as id'd In cm const .h

FUNCS.C

PAGE 1
FLIST (VI . 1/FR) CM

Listed: 26—AUG— 1988 16:55:39

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

7172

73

74

75

76

77

78

79

80

8182

int cm_undeclare(fsm - INPUT

TYPE char *fsm

fsm name string. String must

be nul l-terminated, and must be <= 32

characters In length (excluding NULL),

mbxaccess - INPUT

TYPE Int mbxaccess

is READ | WRITE | XREAD j XWRITE,

but not both of the same kind in the same

declaration. The access constants are

listed In cm const .h. mbxhandle - INPUT

TYPE Int ‘mbxhandle

Variable value was initially set by

cm_deciare and is used as a fast way to

reference a specific mbx. Although this does

not need to be a pointer. It is specified as such for compatabi llty with cmjjeclare

(which requires It) and other common memory

routines.

) PURPOSE: Routine Is used to remove an fsm from a particular mbx's

client list for the specified access. More than one access type may be specified at each call, subject to

the access rules identified in the cm_declare section.

If the action results in a mbx without any clients, the

mailbox Is deleted and the space returned to the operating

system. Likewise, if the action results In an fsm that has

no other mbx's declared, that fsm is removed as a cm client.

If the mbx was identified on the ipjate list, then the

update 1 1st entry wl 1

be purged.

84 RETURNS: status, as id'd in cm const .h

87 int cm write (fsm

88

89

90

9192 mbxhandle

93

94

95

96

97

98

99

100

101 usr data

102

- INPUT

TYPE char ‘fsm

fsm name string. String must

be nul I -terminated, and must be < 32

characters in length (excluding NULL).

- INPUT

TYPE Int ‘mbxhandle

Variable value was Initially set by

cmjleel a re and is used as a fast way to

reference a specific mbx. Although this does

not need to be a pointer, it is specified as such for compatabi I ity with cm_declare

(which requires it) and other common memory

routines.

- INPUT

TYPE byte *usr data

FUNCS.C

PAGE 2
FLIST (VI . 1/FR) CM

Listed: 26-AUG- 1988 16:41:21

103

104

105

106

107

108

109

110

111 112

113

114

115

116

points to user data area from which

bytes are to be transferred.

nr_bytes - INPUT

TYPE Int ‘nrbytes

int variable contains nr of bytes to be

transferred from user data area to common

memory. Although this does not need to be

a pointer, it is specified as such for

compatabi I ity with cm read, which requires it.

) PURPOSE: Routine Is used to transfer the specified number of bytes

from the user data area to the common memory mailbox. Ail

fsm's that have declared READ (or XREAD) access to this mbx

will have an entry made on their ipdate list.

118 RETURNS: status, as id'd In cm const.h

121 int cm

122

123

124

125

126

127

128

129

130

131 132

133

134

135

136

137

138

139

140

141 142

143

144

145

146

147

148

149

150

151 152

153

(fsm

mbxhandle

usr data

nr bytes

read - INPUT

TYPE char *fsm

fsm name string. String must

be nul I -terminated, and must be < 32

characters In length (excluding NULL).

- INPUT

TYPE Int ‘mbxhandle

Variable value was initially set by

cmjjeclare and is used as a fast way to

reference a specific mbx. Although this does

not need to be a pointer. It Is specified as such for compatabi I Ity with cm_declare

(which requires It) and other common memory

routines.

- INPUT TYPE byte *usr_data

points to user data area to which

bytes are to be transferred.

- INPUT/OUPUT

TYPE Int ‘nrbytes

When cmj'ead Is called, if : (1) the int variable « 0, then all data

bytes are transferred from the mailbox

to the user's data area.

(2) the int variable Is not equal to 0,

the nr of bytes transferred will be

min(nr_bytes, nr_bytes_in_mbx).

Upon return, the variable pointed to by

nr_bytes will contain the actual number of

bytes transferred. If fewer bytes are transferred to the user data area than are available in the mailbox, an "informationonly" status of I CM MOREDATA Is returned

FUNCS.C

PAGE 3
FLIST ( Listed:

154

155

156

158

159

160

161

162

163

164

165

167

168

170

174 int

175

176

177

178

179

180

181

182

183

184

185

186

187

188

189

190

192

193

194

195

196

197

198

199

201

202

203

204

V1.1/FR) CM

26-AUG- 1988 16:55:39

to alert the user who may have inadvertently

called cmj'ead without clearing the variable

pointed to by nr_bytes.

It Is the user's responsibility to make

sure that the data area is large enough

to contain the mai I gram*

) PURPOSE: Routine Is used to transfer the specified number of bytes

to the user data area from the common memory mai Ibox.

It is recommended that cm_ckmail be used together with

cmj'ead to minimize common memory accesses.

If an entry for this mbx exists on the update list of this fsm,

it Is removed at completion of the cmj'ead operation.

RETURNS: status, as id'd In cm const .h

cm_ckmai l(fsm - INPUT

TYPE char *fsm

fsm name string. String must

be nui l-terminated, and must be <* 32

characters in length (excluding NULL).

I istjDtr - INPUT

TYPE struct updatej 1st “listjDtr;

If an update list exists for this fsm, cnjckmall

will return a ptr to the top of the

update list in this ixatlon. If none

exists, cmjDkmall will return NULL.

nr^entrles - INPUT

TYPE int *nr_entries;

If an update list exists, the int variable

will contain the number of entries in the

update list; else, It will contain ZERO.

)

PURPOSE: For each fsm that is a READer client of common memory, the common memory manager creates and maintains a list of those

mailboxes that have changed since the last time the fsm read

them (ie, an update 1 1st). Whenever an fsm writes to a common memory mbx, the common memory manager posts an entry

on this “update" list. If an entry already exists for a changed mbx, no additional entry is made. The list is maintained In first- in-first-out (FIFO) order.

Entries are removed from this list whenever an fsm cails

cm read for the respective mailbox. Alternately, an fsm may

call cm ckmail. If an update list exists, cm_ckmail returns a pointer to the top of the list and releases the list to the

FUNCS.C

PAGE 4
FLIST (VI . 1/FR) CM

Listed: 26-AUG- 1 988 16:55:39

205 fsm. If no update list exists, cm_ckmail returns NULL. (The

206 common memory manager will start a new list when the next

207 mbx update arrives.)

209 Once the list is released to the fsm. It is the responsibility

210 of the fsm to FREE the memory allocated for the list. The

211 fsm may do so itself, or it may call cm_free_update_l 1st,

212 passing it a pointer to the top of the list.

214 Using the update list, the fsm can now perform sequential

215 cm_read operations and only access those mai I boxes that have

216 changed since the last read operation.

218 RETURNS: status, as Id'd in cm const .h

221 int cm disc (fsm

222

223

224

225

226 )

- INPUT

TYPE char *fsm

fsm name string. String must

be nul I -terminated, and must be <* 32

characters in length (excluding NULL).

228

229

230

231

232

PURPOSE: Provides a short-cut method for a process to undeclare all of

its mailboxes at one time. All data structures within common memory that are associated with that fsm are freed. The fsm

must Issue a cm_declare before it can again access common memory variables.

234 RETURNS: status, as id'd in cm const .h

238 int cm_get_fsm_l lst(

239 mbxname

240

241

242

243

244

245

246

247

248

249

250

251 I ist type

252

253

254

255

- INPUT

TYPE char ‘mbxname

If NULL, this routine will return, through

fsmj ist_ptr, the list of all fsm names known to the common memory manager.

Arg "list_type" has no effect.

If not NULL, it must point to a mbx name. This routine will return a list of all fsm's

that are a client of that specific mbx. The

arg “l!st_type" Is used to qualify whether

the caller wants the list of READer clients

or the list of WRITer clients.

- INPUT

TYPE char

May only have the values 'R' (READ) and

'W' (WRITE) when ‘mbxname is non-NULL. If *mbxname is NULL, I ist_type Is Ignored.

FUNCS.C

PAGE 5
FLIST (VI . 1/FR) CM

Listed: 26-AUG- 1 988 16:55:39

256

257

258

259

260

261

262

263

264

265

266

267

fsmj istjitr - OUTPUT

TYPE struct fsmj lst_type “fsmj lst_ptr

This routine will create a linked list of fsm names and return a ptr to the top of the

list If any fsm's exists, or NULL if none

exist. It Is the user's responsibility

to free this list when It is no longer needed.

Int_ptr - OUTPUT

TYPE int *lnt_ptr

Upon return, the int variable will equal the

number of entries in the list.

)

269

270

271

272

273

274

275

PURPOSE: This routine allows any fsm to determine what fsm's are currently active In common memory. Using the mbxname and

llstjype appropriately, the caller can retrieve the list of

all fsm's, or only the list of clients (read or write) for a specific mbx. The Information that Is returned on the list can be used to solicit other fsm (and. Indirectly, mbx)

statistics.

277 RETURNS: status, as Id'd in cm const .h

281 int cm_get_mbx_l lst(

282 fsmname

283

284

285

286

287

288

289

290

291

292

293

294

295

298

297 1 1st type

298

299

300

301

302 mbx list ptr

303

304

305

306

- INPUT

TYPE char ‘fsmname

fsm name string. String must

be nul I -terminated, and must be <- 32

characters In length (excluding NULL).

If NULL, this routine will return, through

mbxj fst_ptr, the 1 1st of al I mbx names

known to the common memory manager.

Arg "llstjype" has no effect.

If not NULL, It must point to a fsm name. This routine wi 1

return a 1 1st of al I mbx's

that are a declared by that fsm. The

arg “llstjype" is used to qualify whether

the caller wants the list of READer mbx's

or the list of WRITEr mbx's.

“ INPUT

TYPE char

May only have the values 'R' (READ) and

'W' (WRITE) when ‘fsmname is non-NULL. If ‘fsmname is NULL, list type is ignored. - OUTPUT

TYPE struct mbxj istjype “mbxj ist_ptr

This routine will create a linked list of mbx

names and return a ptr to the top of the

list if any mbx's exists, or NULL if none

FUNCS.C

PAGE 6
FLIST ( L i sted

307

308

309

310

311

312

313

315

316

317

318

319

320

321

323

327 int

328

329

330

331

332

333

334

335

336

338

339

340

341

342

343

344

345

346

347

349

350

351

352

353

354

V1.1/FR) CM

26-AUG- 1 988 16:55:39

exist. It is the user's responsibility

to free this list when it is no longer needed.

Int ptr - INPUT

TPYE int *int_ptr

Upon return, the int variable will equal the

number of entries In the list.

PURPOSE: This routine allows any fsm to determine what mbx's are currently active in common memory. The information that is returned on the list can be used to solicit other cm fsm

(and, indirectly, mbx) statistics. Using the fsmname and

list_type appropriately, the caller can retrieve the list of

all mbx's in common memory, or only the list of mbx's (read

or write) for a specific fsm.

RETURNS: status, as id'd in cm const .h

cm_get_cm_stats(

activity_ptr - INPUT

TYPE cm_act I v I ty_stats *act I v I ty_pt

Points to user-allocated data area of

appropriate size. This routine will copy

the activity statistics into that data area.

It has been implemented In this fashion to

minimize malloc and free operations, since It

is assuned the user will want this information more than once.

client_ptr - INPUT

TYPE cm_c 1 1 ent_stats *c I i ent_ptr

Points to user-allocated data area of

appropriate size. This routine will copy

the client statistics into that data area.

It has been implemented in this fashion to

minimize malloc and free operations, since it

is assumed the user will want this Information more than once.

PURPOSE: This routine provides cm operating statistics.

Since the size of the statistics areas is static,

the user must provide pointers to space in the

data area into which the statistics will be

copied. This avoids malloc overhead in case the

user wishes to call this routine multiple times.

FUNCS.C

PAGE 7

356 RETURNS: status, as id'd in cm const .h
FL I ST ( VI . 1 /FR) CM

Listed: 26-AUG-1988 16:55:39

360

361

362

363

364

365

366

367

368

int cffl_get_fsm_stats(

fsm

ptr

)

- INPUT

TYPE char *fsm

fsm name string. String must

be nul I -terminated, and must be <» 32

characters In length (excluding NULL). - INPUT

TYPE cm_fsm_statsjec *ptr

370

371

372

373

374

375

376

PURPOSE: This routine returns the common memory statistics

for the specified fsm, as Identified In emjsm^statsjec.

Since the size of the statistics area is static,

the user must provide a pointer to space In the

user data area into which the statistics will be

copied. This avoids mailoc overhead In case the

user wishes to call this routine multiple times.

378 RETURNS: status, as id*d in cm const .h

382

383

384

385

386

387

388

389

390

Int cm_getjnbx_stats(

mbx

ptr

)

- INPUT

TYPE char ®mbx

mbx name string. String must

be nul ^terminated, and must be <» 32

characters In length (excluding NULL). - INPUT

TYPE cm mbx stats rec *ptr

392 PURPOSE: This routine returns the common memory statistics

393 for the specified mbx, as identified In cm_mbx_stats_rec.

394 Since the size of the statistics area is static,

395 the user must provide a pointer to space In the

396 user data area into which the statistics will be

397 copied. This avoids mailoc overhead in case the

398 user wishes to call this routine multiple times.

400 RETURNS: status, as id'd In cm const .h

403 V

405 #include "cm uti ls.c“

408 /* 1 1 m 1 1 1 it M 1 1 1 1 1 1 1 1 m i • I I I I I I I II I I I I I I I I II I M Declare a mailbox in common memory. This

FUNCS.C

PAGE 8
FL I ST ( VI . 1 /FR) CM

Listed: 26-AUG- 1988 16:55:39

409 * ! cmjjeclare ! can result in a connection to an already

410 * !!!!!!!!!!!!! !!!!!!!!! existing mbx, or creation of a new one.

411 */

412 int cm_declare (fsm, mbxname, mbxsize, mbxaccess, mbxhandle)

413 char ‘fsm, ‘mbxname;

414 int mbxsize, mbxaccess, ‘mbxhandle;

415 {Int retum_status;

416 byte *data_ptr;

417 fsmjec ‘tmpjsmjec;

418 mbxjec ‘tmpjibxjec;

419 st ruct c I i ent_cha i n *tmp_c I i ent_rec

420 boolean newjsm, newjtox;

422 if ( Inactivity) cm__ln I (); /* Inlt cmm structures */

423 newjsm = FALSE;

424 newjnbx « FALSE;

426 If (retum_status « cm_vai 1 date_fsm( fsm) ) {

427 log_status(&cm_activlty->cm_declare.fal lure, NULL, NULL);

428 return( return status); /* fsm name error V

429 }

430 If (retum_status * cm_va I idate_mbx(mbxname, mbxsize)) {

431 log_status(&cm_activity->cm_declare.fai lure, fsm, NULL);

432 return(return status); /* mbx error V

433 }

434 if (retum_status cm_val Idate_access(mbxacc8ss)) {

435 log_status(&cm_actlvlty->cm_declare.fal lure,fsm,mb>OTame);

436 return( return status); /* inval Id access V

437 }

439 if (tmp_fsm_rec - cm_fsm_f ind(fsm)) {

440 eprlntf(9,"cm_declare: fsm already know to common memoryNn");

441 )else { /* Inlt new rec for this fsm */

442 eprlntf(6,"cm_declare: add 'Xs' as cm cl lent\n",fsm);

443 tmp_fsm_rec * (fsmjec *) malloc (s I zeof( fsmjec));

444 If (tmpjsmjec — NULL) {

445 log status(&cm activity->cm declare. fai lure, fsm, mbxname);

446 retum(E CM INSUFFMEM);

447 }

448 bclr(tmp_fsajec,s I zeof(fsmjec));

449 strcpy(tmpjsmjec->fsmname,fsm); /* save fsm name V

450 new fsm - TRUE;

451 }

453 if (tmpjibxjec = cm_mbx_f lnd(mbxname)){ /* ck If mbx already exists */

454 epr intf(9,"cm_dec7are: This mbx is already-known to common memoryNn");

455 ‘mbxhandle = tmpjibxjec->hand I e

456 }else { /* init new rec for this mbx */

457 epr intf(6,“cm_declare: add '%s' as new cm mbxNn", ntoxname);

458 tmp_mbxjec = (mbxjec *) malloc (sizeof(mbxjec));

459 if (tmp mbx rec = NULL) {

FUNCS.C

PAGE 9
FLIST (V1.1/FR) CM_FUNCS.C

Listed: 26-AUG- 1 988 16:55:39 PAGE 10

460 I og_status(&cm_act I v I ty->cm_dec I are . fa i I ure , f sm .mbxname )

461 return(clear declare(new fsm, new mbx, tmp fsm rec, tmp mbx rec.E CM INSUFFMEM));

462 }

463 bclr(tmpjnbxjec,sizeof(mbx_rec));

464 strcpy( tmpjnbxj'ec->mbxname, mbxname); /* save fsm name */

465 *mbxhandle * ++cmjnbxhandle;

466 tmp_mbx_rec->handle = cm_mbxhandle;

467 tmpjibx_rec->dec I ared length mbxsize;

468 newjnbx = TRUE;

469 data ptr = (byte *) malloc (mbxsize); /* spc aval lable for data mbx ? •/

470 if (data_ptr == NULL) (

471 I og_status( &cm_act I v I ty->cm_dec I are . fa ! I ure , fsm , mbxname )

472 return(ciear declare(new fsm, new mbx, tmp fsm rec, tmp mbx rec.E CM INSUFFMEM));

473 }

474 belr(dataj>tr, mbxsize);

475 tmp mbx rec->data * data ptr;

476 }

478

479

480

481

482

483

484

485

488

487

488

488

490

491

492

493

494

495

496

497

498

499

500

501

502

503

504

505

506

507

508

509

510

if (mbxaccess & CM_XREAD_ACCESS) { /* ck If another fsm has READ or XREAD V

if ( ( tmpjnbx_rec->readers . nr_fsms >1) /* DIE If more than 1 reader V

\\ ((tmpjnbx_rec->readerTist) /* DIE If I'm not the only reader */

&& (f ind_mbx_cllent(tmp_mbx_reC“>readerlist, tmpjsmjec) = NULL))) (

I og_status( &cm_act I v i ty->cm_dec I are . fa 1 1 ure , fsm .mbxname )

return(c I earjjec I are(new_fsm , newjnbx, tmp_fsm_rec, tmpjnbxj’ec , E_CM_MBXNOXREAD ) )

}e!se

if (tmpjc I lentjec « f ind_mbx_c I lent(tmp_mbxjee-»reader list, tmp_fsmjec)){

triple I i ent rec->exc I uslve - TRUE; /* reset from READ to XREAD V

retum^status » l_CMJXJPkBX; /* let user know he was already a client for

* this mbx w/ either READ/XREAD access V

}eise {

«=(tmp_mbx_rec->readers„nrjsms); /* NEW, so increment nr of readers V

44(tmp_fsmj"ec->read.nrjnbxes); /* Incr nr of mbxes this fsm reads V

return^status * addjnbx_cl lent (tmp_fsm_rec, &tmp_mbx_ree->readerl 1st, TRUE);

If (return_status >= EmCM_FATALERR)

return(c lear_dec lare(new_fsm t newjnbx, tmpjsm_rec, tmp_mbx_rec,return_status));

return^status * addjsmjnbx (&tmpJsmj"ee->read.mbxJ ist, tmpjbxjec) ; /* add mbx to fsin's list V

if (return_status >« E_CM_FATALERR) {

I og^status (&cm_act I v I ty->cm_dec I are . fa 1 1 ure , fsm , mbxname )

retum(clear declare(new fsm, new mbx, tmp fsm rec, tmp mbx rec, return status));

}

}

}else

If (mbxaccess & CMJ*EAD_ACCES$) /* ck if another fsm has XREAD V

If ((tmp_mbx_rec->readers.nr_fsms ^ 1) /* DIE If someone has XREAD V

&& ((tmp_mbx_rec->readerllst->exclusive) /* and It Isn't ME V

&& (tmpjnbxj'ec->reader I ist->who 1= tmp_fsm_rec))) {

I og_status (&cm_act i v i ty->cm_dec I are . fa il ure , fsm , mbxname)

return(c learjJec Iare(new_fsm, newjnbx, tmp_fsm_rec, tmp_mbx_rec , E_CMJBXNOREAD ) )

}else

if (tmp_cl ient_rec = f indjnbxjsl lent(tmpjnbxj'ec->readerl 1st, tmp_fsm_rec)){

tmp cl lent rec->exclus7ve * FALSE; /* reset from XREAD to READ V
FL 1ST

L i sted

511

512

513

514

515

516

517

518

519

520

521

522

523

524

525

526

529

530

531

532

533

534

535

536

537

538

539

540

541

542

543

544

545

546

547

548

549

550

551

552

553

554

555

556

557

558

559

560

561

(VI . 1 /FR) CM_FUNCS.C

: 26-AUG- 1988 16:55:39 PAGE 11

retum_status = l_CM_DUPMBX; /* let user know he was already a cl ient for

/* this mbx w/ either READ/XREAD access V

}else {

++(tmp_mbx_rec->readers.nr_fsms);/* NEW, so Increment nr of writers */

++(tmp_fsm_rec->read.nr_mbxes); /* Incr nr of mbxes this fsm reads V

retum_status * add_mbx_cl ient (tmp_fsm_rec, &tmpjnbx_rec->reader I 1st, FALSE);

if (return_status >- E_CM_FATALERR) {

I og_status(&cm_act I v I ty->cm_dec I are . fa 1 1 ure , fsm ,mbxname)

return(clear declare(new fsm, new mbx, tmp fsm rec, tmp mbx rec, return status));

}

retum_status « add_fsm_mbx (&tmp_fsm_rec->read.mbxj 1st, tmpjnbxj’ec); /* add mbx to fsm' s list */

if (return_status >= E_CM_FATALERR) {

log_status(&cm_act iv ity->cm_dec lare.fa i lure , fsm ,mbxname)

return(clear declare(new fsm, new mbx, tmp fsm rec, tmp mbx rec, return status));

}

If (mbxaccess & CM_XWRITE_ACCESS) /* ck If another fsm has WRITE or XWRITE V

If ((tmp_mbx_rec->wrlters.nr_fsms >1) /* DIE if more than 1 writer V

|j ((tmp_mbx_rec->wrlterTist) /* DIE if I'm not the only writer V

&& (f ind_mbx_cl lent(tmpjnbx_rec->wrlterl 1st, tmp_fsm_rec) « NULL))) {

I og_status(&cm_act I v I ty->cm_dec I are . fa 1 1 ure , fsm , mbxname )

retum(clear_declare(new_fsm, new_mbx, tmp_fsm_rec, tmp_mbx_rec,E_CM_MBXNOXWRITE));

)else /* allowed to have XWRITE V

if (tmp_cllent_rec - f lnd_mbx_cl ient(tmp_mbx_rec->wrlterl 1st, tmp_fsra_rec)) {

tmp_cl lent_rec->exclusTve » TRUE; /* reset from WRITE to XWRITE V

retum_status - l_CM_DUPMBX; /* let user know he was already a client for

* this mbx w/ either WRITE/XWRITE access */

}else {

++(tmp_mbx_rec->wr Iters .nr_fsms); /* NEW, so Increment nr of writers */

++(tmp_fsm_rec->write.nr_mbxes); /* Incr nr of mbxes this fsm writes to V

return status « add mbx client (tmp fsm rec, &tmp mbx rec->writerl 1st, TRUE);

If (return_status >- E_CM_FATALERR)~{

I og_status(&cm_act I v I ty->cm_dec I are .failure, fsm .mbxname)

return(clear dec I are (new fsm, new mbx, tmp fsm rec, tmp mbx rec, return status));

}

return_status - addjsra_mbx (&tmp_fsm_rec->write.mbxj 1st, tmp_mbx_rec) ; /* add mbx to fsm's list */

If (retum_status >« E_CM_FATALERR) {

I og_status( &cm_act I v I ty->cm_dec I are . fa 1 1 ure , fsm , mbxname)

return(clear dec I are (new fsm, new mbx, tmp fsm rec, tmp mbx rec, return status));

}

}

else

if (mbxaccess & CM_WRITE_ACCESS) /* ck If other fsm has XWRITE */

if ((tmp_mbx_rec->writers.nr_fsms = 1) /* DIE if someone has XWRITE */

&& ((tmp_mbx_rec->writerTlst->exclusive) /‘and it isn't ME */

&& (tmp_mbx_rec->wrlterl lst->who != tmp_fsm_rec))) {

I og_status (&cm_act I v I ty->cm_dec I are . fa 1 1 ure , fsm , mbxname)

return(clear_declare(new_fsm, new_mbx, tmp_fsm_rec, tmp_mbx_rec,E_CMJBXNOWRITE));

}else /* only add client If not already on list V
FLIST (VI . 1/FR)

Listed: 26-AUG- 1 988 16:55:39

CM_FUNCS.C

PAGE 12

562 if (tmp_cl ient_rec = f IrtijnbxjH ient(tmpjnbx_rec->wrlterl 1st, tmp_fsm_rec)){

563 tmp_c I i ent_rec->exc

uslve - FALSE; /* reset from XWRITE to WRITE *7

564 return_status * l_CM_DUPkBX; /* let user know he was already a client for

565 * this mbx w/ either WRITE/XWRITE access */

566 }else {

567 ++(tmp_mbx_rec->wrlters.nr_fsms); /* NEW, so increment nr of writers V

568 ++(tmp_fsm_rec->write.nr_mbxes); /* incr nr of mbxes this fsm writes to V

569 return status - add mbx_client (tmp fsm rec, &tmp mbx rec->wr iter list, FALSE);

570 if ( returnjtatus >« E_CM_FATALERR)”{

571 I og_status (&cm_act i v I ty->cm_dec I are . fa i I ure , fsm , mbxname )

572 retum(clear declare(new fsm, new mbx, tmp fsm ree, tmp mbx rec, return status));

573 }

574 return status * add fsm mbx (&tmp fsm rec~>wr!te 0 mbx list, tmp mbx rec); /* add mbx to fsm's list

575 If (returnjstatus >- EjMJATALERR) {

576 log_status(&cmraactivity“>cmjjeclare.fal lure,fsm,mbxname);

577 return(elear declare(new fsm, new mbx, tmp fsm rec, tmp mbx rec, return status));

578 )

579 )

582 if (new fsm)

583 if (oitijsmj 1st - NULL)

584 cm fsm list * tmp fsm rec; 585 else {

586 tmpjfsm_reC“>next » cm_fsmj 1st;

587 cm fsm list = tmp fsm rec; 588 }

590 if (new mbx) /* Insert new mbx onto list */

591 if (cmjnbxJ 1st - NULL)

592 cmjibxjist * tmp_mbxjec;

593 else {

594 tmp_mbx_rec->next * cm_mbx_! 1st; /* Insert at front of list V

595 cm mbx list * tmp mbx rec; 596 }

597 log status(&cm activity->cm dec I are. success, fsm, mbxname);

598 if (newjnbx) {

599 -H-(cm_c 1 1 ents->mbx_tt I )

600 ++(cm cl lents->mbx active);

601 }

602 if (newjsm) {

603 ++(cm_c I i ents->fsm^tt I )

604 ++( cm cl lents->fsm active);

Remove a client from a mbx cl lent 1 1st, but

only for the specified access.

605

606

607 }

}

return (return status);

610

611

612

/* 1 1 m 1 1 1 m 1 1 m i m 1 1 1 M ' I I I It II M I II II I M I I II * ! cmjjndeclare

* 1 1 M 1 1 m i 1 1 n 1 1 1 1 1 1

1 1 M 1 1 1 1 M 1 1 1 1 1 1 1 1 1 M

/* insert new fsm onto list */

/* Insert at front of list */
FLIST (VI . 1/FR)

Listed: 26-AUG- 1 988 16:41:21

CM_FUNCS.C

PAGE 13

613 */

614 int cmjjndeclare (fsm, mbxaccess, mbxhandle)

615 char *fsm;

616 Int mbxaccess, *mbxhandle;

617 { Int I, return_status;

618 fsm_rec *tmp_fsm_rec;

619 mbx_rec *tmpjnbx_rec;

620 st ruct c 1 1 ent_cha I n *tmp_c 1 1 ent_rec

622 eprintf(9,“cm_undeclare: fsm %s, access %d, mbxhandle %d\n",

623 fsm, mbxaccess, *mbxhandle);

624 if ( lcm_act I vlty) cm_inl(); /* inlt cmm structures */

625 if ((l(tmp_fsm_rec - cm_fsm_f Ind(fsm))) /* fsm active in cm ? »/

626 I! ( ! (tmp_mbx_rec cm_inbxhandle_f ind(*mbxhandle)))) { /* mbxhandle In cm ? V

627 log status(&cm actlvlty->cm undeclare.fai lure, NULL, NULL);

628 return(E CM kBXNOTDECL);

629 }

630 If (return_status - cm_val ldate_access(mbxaccess)) {

631 I og_status(&cm_act I v I ty->cm_undec I are . fa 1 1 ure , fsm , NULL )

632 return( return status); /* inval Id access */

633 )

635 eprintf(9,"cm undeclare: passed validation testsNn");

636 if (mbxaccess"* (CM_READ_ACCESS | CM_XREAD_ACCESS)) /* is fsm a READ client ? V

637 If (tmp_cl ient_rec « f ind_mbx_cl ient(tmp_mbx_rec->readerl ist,tmp_fsm_rec)) {

638 eprintf(9,“cm_undeclare: found client In readerl IstNn");

639 If ((mbxaccess & CM_READ_ACCESS) && (tmp_cl ient_rec->excluslve)) {

640 log status(&cm activity->cm undeclare.fai lure, fsm, tmp mbx rec-xnbxname);

641 retum(E CM kBXNOTDECL); " /‘DIE if undeclarlng READ but have XREAD V

642 )

643 If ((mbxaccess & CM_XREAD_ACCES$) && (!tmp_cl ient_rec->excluslve)) {

644 log status(&cm activlty->cm undeclare.fai lure, fsm, tmp mbx rec->mbxname)

645 return(E CM kBXNOTDECL); " /‘DIE If undeclarlng )®EAD but have READ V

646 ) 647 del_i|Ddate_rec(tmp_fsm_rec,tmp_mbx_rec->handle); /* remove update notification, if on list V

648 del_mbx_cl7ent(tmp_cl ient_rec,&(tmp_mbx_rec-> reader I lst),&(tmp_mbx_rec->readers.nr_fsms));

649 de l_fsm_mbx_entry(Itmp_fsm_rec->read .mbx_l 1st ,tmp_mbx_rec)

650 —(tmp_fsn_rec->read.nr_mbxes); /* decrease nr of mbxes this fsm reads */

651 eprintf(7,“cm undeclare: deleted READ/XREAD entry\n“);

652 )else {

653 log status(&cm actlvlty->cm undeclare.fai lure, fsm, tmp mbx rec->mbxname);

654 retum(E CM kBXNOTDECL);

655 }

657 eprintf(9,"cm undeclare: finished READ/XREAD checks\n");

658 if (mbxaccess"& (CM_WRITE_ACCESS ! CM_XWRITE_ACCESS)) /* Is fsm a WRITE client ? V

659 if (tnp_cl ient_rec = f7ndjnbx_cl ient(tmp_mbx_rec->wr iterl ist,tmp_fsm rec)) {

660 eprintf(9,“cm_undeclare: found cl lent in writer I IstNn");

661 if ((mbxaccess & CM_WR I TE_ACCESS ) && (tmp_cl lent_rec->exclusive)) {

662 log status(&cm_actlvity->cm undeclare.fai lure, fsm, tmp mbx rec->mbxname);

663 return(E CM kBXNOTDECL); " /‘DIE If undeclar7ng WRITE but have XWRITE */
FLIST (VI . 1/FR)

Listed: 26-AUG- 1988 16:41:21

CM__FUNCS . C

PAGE 14

664 }

665 if ((mbxaccess & CM_XWRITE_ACCESS) && (ltmp_cl lent_rec->excluslve)) {

666 log status (&cm actlvity“>cm undec I are . fa! I ure , fsm , tmp mbx rec->mbxname)

667 retum(E CM fcBXNOTDECL); ” /‘DIE if undec larlng XWRITE but have WRITE V

668 }

669 de I _mbx_c I lent(tmp_cl lentj’ec,&(tmpjnbxj"ec->wr Iter I i st ) , &( tmpjnbx_rec->wr iters.nr_fsms));

670 de I _fsm_mbx_entry(&tmp_fsm_rec->wr ite.mbxj ist,tmp_mbx_rec)

671 —(tmp_fsm„r0C->wr| te„nr_inbxes); /* decrease nr of mbxes this fsm writes */

672 eprintf(7,"cm undeciare: deleted WRITE/XWR ITE entry\n“);

673 }else {

674 log status(&em actlvlty->cm indeclare.fal lure, fsm, tmp mbx rec->mbxname);

675 return(E CM MBXNOTDECL);

676 }

678 /* if mbx has no other clients, remove it from cmjnbxjist */

679 if ((ltmpjnbxjee-»readerl 1st) && (itmpjnbxjee->wrTterl 1st)) {

680 ~(om_c I i ent$->mbx_act i ve)

681 cm mbx del (tmp mbx rec);

682 }

684 /* if the fsm has no other mailboxes declared, remove It from em fsmJ 1st V

685 if ((ltmp_fsm_rec->read.mbx_l 1st) && (ltmp_fsmjec->write.mbxJ 1st)) {

686 —(cm_c I i ents->fsm_act I ve)

687 cm fsm del (tmp fsm rec);

688 }

689 log status(&cm actlvlty->cm undec I are. success, fsm, tmp mbx rec->mbxname);

690 return (I CM OK);

691 }

Transfer the specified number of bytes from the

the user data area to the common memory mbx.

usr data, nrbytes)

702 ( fsm_rec *tmp_fsm_rec;

703 mbxjec *tmpjnbx_rec;

704 timestamp when;

706 eprintf(5, Mcm_write: at entry, fsm * %s, mbxhandle * %d, nrbytes = Xd\n\

707 fsm, ‘mbxhandle, ‘nrbytes);

709 if ( !cm_act i vity) cm_inl(); /* init cmm structures */

710 if ( ( ! (tmp_fsm_rec = cm_fsm_f Ind(fsm))) /* fsm active In cm ? */

711 || ( ! (tmp_mbx_rec = cm^mbxhand I e_f i nd( ‘mbxhand I e ) )) ) (/* mbxhandle in cm ? */

712 log status(&em activ!ty->cm wr ite. fa i lure, NULL, NULL);

713 return(E CM ^XNOTDECL);

714 }

694

695

696

697

698

699

700

701

/*

*

li M I I I I I I I I I II I I I I I I t

I I I I I I I I I I I I I I I I I I I II I cm write

I I I I I I I I I M I I I i M I I I I I

I I I I I I I I I I II I II I I I I M I V

int cm_wr!te (fsm, mbxhandle,

char ‘fsm;

byte ‘usrjlata;

int *mbxhandle, ‘nrbytes;
FLIST (VI . 1/FR)

Listed: 26-AUG- 1 988 16:41:21

CM__FUNCS . C

PAGE 15

715 if (If indjnbx_cl ient(tmpjnbx_rec->writerl ist,tmp_fsm_rec)) {

716 log status(&cm activity->cm write. fai lure, fsm, tmp mbx rec->mbxname)

717 return(E CM KBXNOTDECL); ” /* not a'wRITE/XWRITE cl lent of this mbx V

718 }

719 if (*nrbytes > tmp_mbx_rec-xjec I ared length) {

720 log_status(&cm_act lvity->cm_wr Ite .fa i lure, fsm, tmpjitoxj'ec->mbxname)

721 return(E CM M5XSIZE); /* attempt to write more than mbx space allows */

722 }

723 eprintf(5,"cm_write: passed validation tests\n");

724 if (‘nrbytes) /* transfer data to mbx */

725 bcpy(usr_data , tmp_mbx_rec->data , ‘nrbytes)

726 tmp_mbx_rec->msg length - ‘nrbytes; /* nr bytes In msg */

727 ++(tmp_mbx_rec->wr I ters .nr_accesses)

728 tmp_mbx_rec->writers.who * tmp_fsm_rec;

729 tlme(&when); /* timestamp */

730 tmp_mbx_rec->wr I ters. when - when;

731 tmp_fsm_rec->wr Ite. when when;

732 ++(tmp_fsm_rec->wr I te .nr_accesses)

733 tmp_fsm_rec->wr I te . mbxhand I e *mbxhandle;

735 /* notify al I READ cl lents of this mbx that a change has occured in the mbx */

736 not I fy_c 1 1 ents( tmp_mbx_rec->reader list, ‘mbxhand I e)

737 log status (&cm actlvity->cm wr Ite. success, fsm, tmp mbx rec->mbxname);

738 returnd CM OK);

739 }

743

744

745

746

747

748

749

750

751

752

753

754

/*

*

1 1 1 1 1 1 ii 1 1 m 1 1 1 ii n 1

1 1 1 1 1 1 1 1 1 1 1 1 1 1 ii 1 1 1 1

i

i _

1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1

1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1

cm read

V

int cmjead (fsm, mbxhand le,

char *fsm;

byte *usr_data;

int ‘mbxhand le, ‘nrbytes;

{ fsm_rec *tmp_fsm_rec;

mbx_rec *tmp_mbx_rec;

timestamp when;

int return status;

Transfer the specified number of bytes from the

the common memory mbx to the user data area.

usr data, nrbytes)

756 epr!ntf(5,"cm_read: at entry, fsm « Xs, mbxhandle = %d, nrbytes » %d\n",

757 fsm, ‘mbxhandle, ‘nrbytes);

758 If ( !cm_act I vity) cm_ I n I ( ) ; /* initialize cmm structures */

759 return_status = l_CM_0K; /* assume clean exit */

760 if ((!(tmp_fsm_rec = cm_fsm_f Ind(fsm))) /* fsm active In cm ? */

761 !i (!(tmp_mbx_rec = cm_mbxhand I e_f I nd( ‘mbxhand I e ) ) ) ) { /* mbxhandle in cm ? */

762 I og status(&cm_act I v I ty->cm read . fa 1 1 ure , NULL , NULL )

763 return(E CM NBXNOTDECL)

764 }

765 if (Ifind mbx client(tmp mbx rec->reader 1 1st, tmp fsm rec)) {
FLIST (VI . 1/FR) CM

Listed: 26-AUG- 1 988 16:41:21

766 log status(&cm activity->cm read.fai lure, fsm, tmp mbx rec-xnbxname);

767 return(E CM M3XN0TDECL); ” /* not a READ/XREAD client of this mbx */

768 }

769 if ((‘nrbytes < tmp_mbx_rec->msg length) && (*nrbytes)) {

770 I og_status(&cm_act I v7ty->cm_read .failure, fsm , tmpjnbx_rec->mbxname )

771 return status = I CM MOREDATA; /* user wants to read less than available V

772 }

773 else ‘nrbytes = tmp_mbx_rec->msg length;

774 eprintf(5,“cm_read: passed validation tests\n");

775 if (*nrbytes) /* transfer data to mbx */

776 bcpy(tmp_mbx_rec->data,usr_data ,*nrbytes)

777 ++(tmpjnbx_rec->readers .nr_aecesses)

778 tmpjnbx_rec->readers.who - tmp_fsmjec;

779 time(&when); /* timestamp V

780 tmpjnbx_rec->readers. when when;

781 tmp_fsmjec->read.when » when;

782 ++ (tmp_fsm_rec->read . nr_accesses )

783 tmpjfsm_rec->read .mbxhand le « ‘mbxhandie;

785 /* Check if fsm has an update record for this mailbox in his update list. V

786 /* If found, remove it. V

787 de I jjpdatejec( tmp_fsm_rec , *mbxhand I e)

788 i og^status (&cm_act7v ! ty->cm_read . success , fsm , tmpjnbx_rec->mbxname )

789 return (return status);

790 }

793

794

795

796

797

798

799

800

801

/* hi f Miiumimmiiiii

* | cn^ckmail

* iimiimimmim i i i i 1 1 1 1 i i 1 1 1 1 1 1 1 n 1

V

int cm_ckmai l(fsm, list_ptr, nr^entries)

char *fsm;

struct updatejist **list_ptr;

int *nr_entries;

{ fsm rec *tmp fsm rec;

Pass the fsm the update 1 1st if one exists, or pass It NULL If none exists.

803 eprintf(9,“cm_ckmai 1: at entry, fsm * %s\n" , fsm);

804 if ( !cm_act i vTty) cmJniQ; /* initialize cmm structures V

805 If ( ! (tmp fsm rec - cm fsm find(fsm))) { /* fsm active in cm ? V

806 log status(&cm act i v lty->cm_ckma 1 1. success, NULL, NULL);

807 return(E CM MBXNOTDECL);

808 ) 809 if (tmpjfsm_ree->update_top) { /* if update list exists, send it */

810 *list_ptr = tmp_fsm_rec->update_top;

811 *nr_entries = tmp_fsm_rec->nr_updates;

812 tmp_fsm_rec->update_top = NULL; /* reset V

813 tmpJsm_rec->update_bot - NULL;

814 tmp_fsm_rec->nr_updates - 0; 815 }else {

816 ‘list ptr = NULL;

FUNCS.C

PAGE 16
FLIST (VI . 1/FR)

Listed: 26-AUG- 1 988 16:41:21

CM_FUNCS.C

PAGE 17

817 *nr entries = 0; 818 }

819 log status(&cm activlty->cm ckma 1 1 .success, f sin, NULL);

Pass the fsm the update list If one exists, or pass it NULL If none exists.

lent rec;

837 eprlntf(9,"cm_disc: at entry, fsm - %s\n", fsm);

838 if ( !cm_act I vTty) cm_lni(); /* Initialize cmm structures V

839 if ( I (tmp_fsm_rec - cm_fsm_f ind(fsm))) { /* fsm active In cm ? V

840 log status (&cm actlvity->cm disc. success, NULL, NULL);

841 return(E CM fcBXNOTDECL);

842 }

843 cm_free_Lpdate_l ist(tmp_fsmjec->update_top); /* free the update list V

845 while (tmp_fsm_rec->read.mbxj 1st) { /* process the READ/XREAD list V

846 tmpjnbxjec « tmp_fsm_rec->read.mbx_l lst->mbx;

847 epr7ntf(7,“cm_dlsc: processing read mbx Xs\n“ ,tmp_mbx_rec->mbxname)

848 if (tmpjc I lentjec « f ind_mbx_cl lent(tmp_mbx_rec->readerl ist,tmp_fsm_rec)) {

849 del_mbx_cllent(tmp_cl lentjec, &(tmp_mbx_rec->readerl 1st), &(tmp_mbx_rec->readers.nr_fsms));

850 if ((ltnp_mbx_rec->readerTlst) && (ltmp_mbx_rec->wrlterl 1st)) {

851 eprlntf(7,"cm_disc: Xs has no more clients... freed\n",tmp_mbx_rec->mbxname);

852 —(cm_c I lents->mbx_act I ve)

853 cm mbx del(tmp mbx rec); /* delete mbx If it has no more clients V

854 }

855 }else {

856 prlntf("cm_disc: FATAL ERROR: attempt to undeclare mbx for which fsm Isn't cl lent. \n"

857 "Contact the network team.Xn");

858 ex It (0x40);

859 }

860 tptr = tmp_fsm_rec-> read. mbxj 1st;

861 tmp_fsm_rec->read.mbx_l 1st = tmp_fsm_rec->read.mbxj ist->next;

862 free(tptr);

863 )

865 whi le (tmp_fsm_rec->wrlte.mbx_l ist) ( /* process the WR ITE/XWR ITE 1 1st V

866 tmp_mbx_rec = tmp_fsm_rec->wr ite.mbxj lst->mbx;

867 eprlntf(7,"cni_disc: processing write mbx %s\n“,tmp_mbx_rec->mbxname);

820

821

return (I CM OK);

824

825

826

827

828

829

830

831

832

833

834

835

1 1 it 1 1 1 1 ii i ii ii m 1 1 1 1

1 1 1 1 1 1 1 1 1 1 ii i ii 1 1 1 ii 1

i

i

1 1 1 1 1 1

1 1 1 1 1 1

cm_disc

1 1 1 1 1 1 1

1 1 1 1 1 1 1

1

1

1

1

*/

Int cm_dlsc(fsm)

char *fsm;

{ int return_status;

byte *dataj)tr;

fsrnjec *tmp_fsmjec;

mbx_rec *tmp_mbx_rec;

struct cl lent_chain *tmp_cl

struct mbx dec I chain *tptr
FLIST (VI . 1/FR)

Listed: 26-AUG-1988 16:41:21

CM_FUNCS.C

PAGE 1

868 i f ( tmp_c I i ent_rec - f i ndjnbx_c 1 1 ent ( tmpjnbx_rec->wr i ter 1 1 st , tmp_fsm_rec ) ) {

869 de I _iiibx__c I i ent ( tmp__c 1 1 ent__rec , &(tmp_mbxjec->wrlterl 1st), &(tmp_mbx_rec->readers .nrjsms))

870 if 7( Itmp_mbx_rec->reader7 1st) && (ltmpjnbx_rec->writerl 1st)) {

871 —(cm_cl ients->mbx_active);

872 epr intf(7/cmjjisc: %s has no more clients... freedNn" ,tmp_mbx_rec->mbxname);

873 cm mbx del(tmp mbx rec); /* delete mbx if it has no more clients */

874 }

875 }else {

876 printf(“cm_disc: FATAL ERROR: attempt to undeclare mbx for which fsm isn't client. \n“

877 "Contact the network team.Nn");

878 ex it (0x40);

879 }

880 tptr * tmpJsmjec^write. mbxj 1st;

881 tmpJsm_rec~>wr i te .mbx_ list* tmpJsmjec->wr i te .mbx^ I i st->next

882 free(tptr);

883 }

885 /* fsm should have no other mailboxes declared,, so remove It from cmJsmJ Ist */

886 If ((!tmp_fsm_rec->read.mbxj 1st) U ( Stmpjsffljee^wrlte.mbxj 1st)) {

887 —(cm_c 1 1 ents=>fsnjact I ve)

888 cm fsm del (tmp fsm rec);

889 }e!se{

890 prlntf("cm_dlse: Didn't work... still have read/write clients for this fsm.Vf

891 "Contact the network team.Nn");

892 exlt(0x40);

893 }

894 log status(&cm activlty->cm dlsc.success, fsm, NULL);

895 returnd CM OK);

898 }

899

900

901

902

903

904

905

906

907

908

i m 1 1 i m i 1 1 1 1 1 1 1 i g n

I I « I I! II I 8 I I I I I « I I II cnjptjnbxJ ist

1 1 1 s 1 1 s sTiiTi 1 1 1 1 1

1 1 1 1 1 1 1 u m 1 1 1 1 1 1 1 1

Construct a I Inked list of mbx names and return

a pointer to It to the caller. If fsmname ** NULL

return a list of all mbx's in cm; else return the

list of mbx's of the specified fsm and for the

specified list type access. /

int cmjgetjnbxJ ist(fsmname, listjype, mbxJIstjDtr, int_ptr)

char ‘fsmname, listjype;

struct mbxj istjype “mbxj ist_ptr;

int ‘int ptr;

909 { struct mbxj istJype ‘tptr;

910 fsmjec *tmpjsm_rec;

911 mbxjec ‘tmpjnbxjec;

912 st ruct mbxjec 1 _cha i n *tmp_c 1 1 entjec

913 int return^status;

915 if ( lcm_activity) cm_ i n i ( )

/* initialize cmm structures */

916 ‘mbxj istjtr = NULL; /* initialize ptr */

917 ‘int_ptr * 0; /* initialize nr entries on list */

918 if (7(tmp mbx rec = cm mbx list))
FLIST (VI . 1/FR)

Listed: 26-AUG- 1 988 16:41 : 2

CM_FUNCS.C

PAGE 19

919

920

921

922

923

924

925

926

927

928

929

930

931

932

933

934

935

936

937

938

939

940

941

942

943

944

945

946

947

return(l_CM0K); /* no mbx's in cm */

tmp_cl ientjec - NULL;

If (fsurname) { /* Is a mbx name provided ? V

if (return_status = cm_val ldate_fsm(fsmname)) {

eprintf(9,

M cmjjetjnbx_l 1st: Invalid fsm name 'Xs'Nn", fsmname);

1 og_status(&cm_act I v i ty->cm_get_mbx_ I ist.fal lure, NULL, NULL);

return(retum status); /* fsm error V

}If ( I (tmp_fsmjec = cm_fsm_f lnd(fsmname))){ /* ck If fsm exists V

eprintf(9,"cm_get_mbx_llst: fsm 'Xs' doesn't exist in cm\n",fsmname);

log status(&cm actlvity->cm get mbx I Ist.fal lure, fsmname, NULL);

return(E CM FSMNOT I NCM)

}

switch ( I ist_type) { case 'R': case 'r':. tmp_clientjec - tmp_fsm_rec->read.mbxj 1st;

eprlntf(9,"cm_getjnbxjist: for fsm 'Xs', read I lst\n", fsmname);

break; case 'W': case 'w': tmp_cllent_rec « tmp_fsm_rec->wrlte.mbxj 1st; eprTntf(9,"cm_get_mbxJ 1st: for fsm 'Xs', write 1 1st \n", fsmname);

break;

default : eprintf(9,“cra_get_mbx_l 1st: Invalid llst_type 'Xc' for fsm 'Xs'\n“, I ist_type, fsmname);

log status(&cm actlvl?y->cm get mbx I ist.fal I ure, fsmname, NULL);

return(E CM MBXACCESS);

}

tmp_mbx_rec « NULL; /* so only tmp_cl lent_rec is used V

}else /* no fsm name... get all mbx's */

eprintf(9,

Hcm_get_mbx_l 1st: no fsm name specif led\n“);

949 /* bui Id the list of fsm names V

950 while ((tmpjnbxj'ec) \\ (tmp_cilent_rec)) {

951 tptr « (struct mbx list type *) raalloc (sizeof (struct mbx list type));

952 If (tptr) (

953 be I r(tptr, sizeof(struct mbxj ist_type));

954 if (fsmname)

955 strcpy(tptr->mbxname,tmp_cl ient_rec->mbx->mbxname);

956 else strcpy(tptr->mbxname ,tmp_mbx_rec->mbxname )

957 tptr->next - *mbx_l lst_ptr;

958 *mbx_l lst_ptr « tptr;

959 If (fsmname)

960 tmp_cl ient_rec * tmp_cl lent_rec->next;

961 else tmp_mbx_rec - tmp_iiibx_rec->next

962 ++(*lnt_ptr);

963 )else{ /* else, out of memory V

964 eprlntf(9,"cm_getjibxJ 1st: ran out of memory\n");

965 while (tptr = *mbx_l ist_ptr) { /* free the list */

966 *mbx_l ist_ptr = (*mbx_l ist_ptr)->next;

967 free(tptr);

968 ) 969 *int ptr = 0;
CM_FUNCS.C

PAGE 20

FL I ST ( VI . 1 /FR)

Listed: 26-AUG- 1 988 16:41:21

970 log status(&cm activity->cm get mbx I ist.fai lure,fsmname,NULL);

971 retum(E CM INSUFFMEM);

972 }

973 }

974 I og__status (&cin_act i v i ty->cm_get__mbx_ 1 1st . success, fsmname,NULL);

975 return(l CM OK); /» nothing to report V

976 }

979

980

981

982

983

984

985

986

987

988

989

990

991

992

/*

*

1 1 1 1 ii 1 1 ii m 1 1 ii t it 1

1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 n 1 1

cmjetjsmj 1st i

I I I I I I I I I I I M II I I I I I I

I I I I I I I I II I I I I I I I II I I

Construct a linked list of fsm names and return

a pointer to the cal ler. If mbxname «= NULL then

return all cm clients; else return I Istjype

clients of the specified mbx.

V

int cmjetJsm_1 1 st (mbxname, I istjype, fsmjlstjtr, intjtr)

char ‘mbxname, ! istjype;

struct fsmj Istjype “fsraj Istjtr;

int * Intjtr;

{ struct fsmj istjype *tptr;

fsmjec ‘tmpjsmjee;

mbxjec ‘tmpjnbxjec;

struct c 1 1 entjha I n *tmpj1 1 entjec

Int return status;

/* Initialize cmm structures •/

/* Initial ize ptr •/

/* Initialize nr entries on list */

/* no fsm's in cm V

994 If (Icm activity) cm inl();

995 *fsmj Istjtr « NULL?

996 ‘intjtr « 0;

997 If (7(tmpJsmjec * cm_fsm_l 1st))

998 return? I JMJK);

999 tmpjl ientjec « NULL;

1000 if (mb^ame) { /* Is a mbx name provided ? V

1001 if (returnjtatus * cmva i I datejnbx(mbxname s 1 ) ) { /* fake the mbxsize V

1002 epr I ntf (9 , "cmjetJsre_ list: Tnva 1 1 d mbxnameNn “ )

1003 logjtatus(&mjctivity->cmjetJsnM ist.fai lure, NULL, NULL);

1004 retum(return status); /* mbx error */

1005 }

1006 If ( I (tmpjnbxjec * cmjbxJ I nd(mbxname) ) ) { /* ck if mbx exists */

1007 epr I ntf(9, "cmjetjsmj 7st: mbxname doesn't exist In cm\n");

1008 log status(&cm activity~>cm get fsm I ist.fai lure, NULL, mbxname);

1009 return(E CM MBXNOTDECL);

1010 }

1011 switch (1 1st type) {

1012 case 'R'f

1013 case 'r': tmpjl Ientjec = tmpjbxjec->readerl 1st;

1014 epr7ntf(9,“cmjetjsmjist: for mbx '%s\ reader! 1st \n\ mbxname);

1015 break;

1016 case 'W': 1017 case 'w': tmpjl Ientjec = tmpjbxjec->wrlterl 1st;

1018 epr7ntf(9,"cmjetJsmJ 1st: for mbx '%s\ wr iter I ist\n", mbxname);

1019 break;

1020 default : eprlntf(9,

H cmjetJsmJ 1st: invalid listjype '%c' for mbx '%s'\n",l I stjype, mbxname);
FLIST (VI . 1/FR)

Listed: 26-AUG- 1 988 16:41:21

CM_FUNCS .

PAGE 21

1021

1022

1023

1024

1025

1026

1028

1029

1030

1031

1032

1033

1034

1035

1036

1037

1038

1039

1040

1041

1042

1043

1044

1045

1046

1047

1048

1049

1050

1051

1052

1053

1054

1055

1058

1059

1060

1061

1062

1063

1064

1065

1066

1067

1068

1069

1070

1071

log status(&cm act i v i ty->cin get fsm I ist.fai lure, NULL, mbxname);

return(E CM MBXACCESS);

}

tmp_fsm_rec = NULL; /* so only tmp_cl ient_rec Is used V

}else /* no mbx name... get all fsm's V

eprintf(9,"cm_get_fsmj 1st: no mbxname specif led\n“);

/* bui Id the list of fsm names V

while ((tmp_fsm_rec) (tmp__c I ient_rec)) {

tptr - (struct fsm list type *) malloc (s I zeof (struct fsm list type));

if (tptr) {

be I r (tptr .slzeof (struct fsmj ist_type));

If (mbxname)

strcpy(tptr->fsmname , tmp_c I I ent_rec->tfio->fsmname)

e I se strcpy(tptr->fsmname ,tmp_fsra_rec->fsmname )

tptr->next - *fsm_l I st_ptr

*fsra_l ist_ptr - tptr;

if (mbxname)

tmp_cl lent_rec = tmp_cl ient_rec->next;

else tmp_fsm_rec » tmp_fsm_rec->next;

++(*int_ptr);

)else{ /* else, out of memory V

eprintf(9,“cm_get_fsmj 1st: ran out of memoryVT);

while (tptr - *fsmjist_ptr) { /* free the list V

*fsm_l ist_ptr - (*fsm_l lst_ptr)->next;

free(tptr);

)

*int_ptr » 0; log status(&cm actlvity->cm get fsm I ist.fai lure, NULL .mbxname);

retum(E CM INSUFFMEM);

)

}

log_status(&cm_act I vl ty->cm_get_fsm_l 1st .success .NULL .mbxname)

return(l CM OK); /* nothing to report */

)

/* 1 1 1 1 1 1 it

m Mit 1m / 1 1 M 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1

* ! cm_get_cm_stats

* 1 1 1 1 1 1 1 1 1 1 M 1 1 1 1 1 1 1 1

M 1 1 M 1 1 M 1 1 1 1 1 1 1 1 1 1

*

**/

Since the size of the statistics areas Is static,

the user must provide pointers to space In the

user data area into which the statistics will be

copied. This avoids malloc overhead in case the

user wishes to call this routine multiple times.

int cm_get_cm_stats(actlv!ty_ptr, cllent_ptr)

cm_act7v I ty_stats *act I v I ty_ptr

cm cl ient_stats *cl lent ptr;

{ "

if ( lcm_act I vity) cmJniQ; /* Initialize emm structures */

if (CM_GET_STATS) { /* collecting stats ? V

bcpy(cm_activity, activity_ptr, slzeof(cm_activlty_stats));

bcpy(cm clients, client ptr, sizeof(cm client stats));
FL I ST (VI . 1 /FR)

Listed: 26-AUG— 1988 16:41:21

CM_FUNCS.C

PAGE 22

1072 eprintf(9,"cm get cm stats: stats transferred to user area\n");

1073 }else{

1074 eprintf(9,

M cm_get_cm_stats: cm is not logging stats\n“);

1075 bclr(activlty_ptr, sTzeof(cm_actlvity_stats));

1076 bcl r(cl lent ptr, sizeof(cm client stats));

1077 )

1 078 log_status(&cm_act i v i ty->cmjetjmjtats .success , NULL , NULL)

1079 retum(i CM OK); /* nothing to report V

1080 }

1083 /*

1084 *

1085 * 1086 *

1087 *

1088 V

1089 Int cmjet_fsm_stats( fsra , ptr)

1090 char *fsm;

1091 cm_fsm_$tats_rec *ptr;

1092 { fsmjee *tmp_fsm_rec;

1093 mbxjee ‘tmpjnbxj'ec;

1094 int return status;

1 1 1 m m 1 1 m M 1 1 1 1 1 1 1

M i M 1 1 1 1 1 1 M 1 1 1 M 1 1

cmjet_fsm_stats

i i i i i i i i i iiTi i ii i ii

1 1 1 1 1 1 m 1 1 1 1 1 1 1 1 1 1 1 1

Since the size of the statistics area is static,

the user must provide a pointer to space in the user data area into vnhich the statistics will be

copied. This avoids malloc overhead in case the

user wishes to call this routine multiple times.

1096 if (Icmjctivity) cmJnlQ; /* Initialize cmm structures */

1097 if (retumjtatus « cm_val idate_fsm(fsm)) {

1098 eprintf(9,"cmjet_fsm_stats: invalid fsm name 'Xs'\n“,fsm);

1099 logjtatus(8.cmjet ivlty->cmjetJsm_stats.fai lure, NULL, NULL);

1100 return(return status); /* fsm error */

1101 }

1102 if ( I (tmp_fsmjec « cm_fsm_f lnd(fsm))){ /* ck if fsm exists V

1103 eprintf(9,"cmjetJsmjtats: fsm '*s' doesn't exist In cm\n"»fsm);

1104 log status(&cm activlty-»cm get fsm stats. fal lure, fsm, NULL);

1105 return(E CM FSMNOTiNCM);

1106 ) 1107 ptr->nrj'eadjnbx * tmp_fsmjec->read.nr_mbxes;

1108 ptr->nr reads = tmp_fsm_rec->read . nr ^accesses

1109 ptr->read_time » tmp_fsmjec->read.when;

1110 if ( tmpjsmj'ec-»read.mbxhand le I- 0) {

1111 tmpjnbxj'ec = cmjnbxhand i e_f i nd(tmp_fsm_rec->read . mbxhand I e)

1112 (tmpjnbxj'ec) ? strcpy(ptr->mbxj'ead,tmpjnbxj'ec->mbxname)

1113 : sprintf(ptr->mbx read /mbxhand ie %d\tmp fsm rec->read. mbxhand I e);

1114 }eise

1115 spr i ntf (ptr->mbx_read

, “<none> “ )

1116 ptr->nr_wr Itejnbx = tmp_fsm_rec->write.nr_mbxes;

1117 ptr->nr_writes = tmpjsm_rec->write.nr_accesses;

1118 ptr->wr7te_t ime tmp_fsm_rec->wr I te .when;

1119 if ( tmp_fsm_rec->wr i te . mbxhand I e != 0) {

1120 tmpjnbxj'ec = cmjnbxhandle_f ind(tmp_fsmjec->write. mbxhand le);

1121 (tmpjnbxj'ec) ? strcpy(ptr->mbxjrite,tmpjnbxj°ec->mbxname)

1122 : sprintf(ptr->mbx wr ite, "mbxhand I e %d",tmp fsm rec->wr i te. mbxhand I e);
FLIST (VI . 1/FR)

Listed: 26-AUG- 1988 16:41:21

CM__FUNCS . C

PAGE 23

1123 }else

1124 spr Intf (ptr->mbx_wr i te

, "<none>M )

1125 ptr->nr_updates - tmp_fsm_rec->nr_updates

1126 log status(&cm actlvlty->cm get fsm stats. success, fsm, NULL);

1127 returnd CM OK);

1128 )

1131 /*

1132 *

1133 *

1134 *

1135 *

1136 V

1137 int cm_getjnbx_stats(mbx, ptr)

1138 char *inbx; 1139 cm_mbx_stats_rec *ptr;

1140 { fsm_rec *tmp_fsm_rec;

1141 mbx_rec •tmpjnbxj'ec;

1142 Int return status;

m i M i M 1 1 1 1 m 1 1 1 1 1 1

1 1 1 1 1 1 1 1 1 1 1 1 M 1 1 1 1 1 1

cm_get_mbx_stats

1 1 1 1 1 1 1 1 1 1 1 1 M 1 1 1 1 1 1

1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1

Since the size of the statistics area is static,

the user must provide a pointer to space In the

user data area Into which the statistics will be

copied. This avoids malloc overhead in case the

user wishes to call this routine multiple times.

1144 if ( lcm_act I vlty) cmjnl(); /* Initialize cmm structures V

1145 if (return_status « cm_val idate_mbx(mbx,1)) { /* fake a mbxslze */

1146 epr intf(9,"cm_get_mbx_stats: inval Id mbx name 'Xs'\n\mbx);

1147 log_status(&cm_activity->cm_get_mbx_stats.fal lure, NULL, NULL);

1148 retum(return status); /* fsm error V

1149 )

1150 If ( I (tmp_mbx_rec - cm_mbx_f ind(mbx)))( /* ck if fsm exists V

1151 epr!ntf(9,"cm_getjnbx_stats: mbx 'Xs' doesn't exist In cm\n",mbx);

1152 log status(&cm actlvlty->cm get mbx stats. fal lure, mbx, NULL);

1153 return(E CM kBXNOTDECL);

1154 }

1156 pt r->handle * tmp_mbxjec->handle;

1157 ptr->declared length » tmp_mbx_rec->dec I ared length;

1158 ptr->msg length - tmp_mbx_rec->msg length;

1159 ptr->readjfsms * tmp_mbx_rec->readers.nr_fsms;

1160 ptr->read_accesses - tmp_mbx_rec->readers .nr_accesses

1161 ptr->read_time - tmp_mbx_rec->readers.when;

1162 (tmp_mbx_rec->readers.who) ? strcpy(ptr->reader,tmp_mbxjec->readers.who->fsmname)

1163 : spr intf (ptr->reader,"<none>");

1164 ptr->wrlte_fsms = tmp_mbx_rec->wrlters.nr_fsms;

1165 ptr->wr ite_accesses = tmp_mbx_rec->writers.nr_accesses;

1166 ptr->write_time = tmp_mbx_rec->wr iters. when;

1167 (tmp_mbx_rec->wr iters. who) ? strcpy(ptr->wrlter,tmp_mbx_rec->writers.who->fsmname)

1168 : sprlntf(ptr->writer,"<none>“);

1169 (tmp_mbxjec->reader I ist->exc lus ive)

1170 ? strcpy(ptr->xreader,tmp_mbx_rec->readerl ist->who->fsmname)

1171 : spr intf (ptr->xreader,"<none>");

1172 (tmpjnbx_rec->writerl ist->excluslve)

1173 ? strcpy(ptr->xwriter,tmp mbx rec->writerl lst->who->fsmname)
FLIST (VI . 1/FR)

Listed: 26-AUG- 1988 16:41:21

CM_FUNCS .

PAGE 24

1174 : sprintf(ptr->xwriter/<none>");

1175 log status (&cm act I v i ty->cm get mbx stats. success, NULL, mbx);

1176 retumd CM_0K);

1177 }
FL I ST (VI . 1 /FR) CM

Listed: 26-AUG- 1988 16:42:08

1 /* cm uti Is.c 2

3

4

contains the following utility routines (in the order

shown). These are primarily used by the common memory

interface routines (in file cm_fmcs.c), but are also

accessible to the user.

8 eprintf - displays variable- length arg list using fmt

9 IF level <- DEBUG_LEVEL. As written, is

10 specific to Turbo C.

12 cm_f ree_mbx_cl lentj ist - FREE the

13 deleting

15 cm_f ree_fsm_mbx_l Ist - FREE the

16 deleting

mbx's entire client list in preparation for

the mbx.

fsm's entire mbx list in preparation for

the fsm entry.

18 cm free update list - Free all memory allocated to an update list.

20 cm_fsm_f Ind - Check If the fsm is on the cm's client list.

21 If found, return ptr; else return NULL.

23 cm mbx find

24

26 cm_mbx_de

28 cm_fsm_de

30 cm mbxhandle find

31

33 find mbx client

34

35

37 addjnbx_cl lent

39 del_mbx_cl lent

41 f ind_fsm_mbx

43 add_fsm_mbx

45 del fsm mbx entry

46

- Check if the mbx is already in the cm.

If found, return ptr; else return NULL.

- Remove a mailbox entry from the cmjnbxJIst.

- Remove an fsm entry from the cm_fsm_l 1st.

- Find the mbx record associated w/ this mbxhandle.

Return NULL if not found.

- Check if the fsm Is on this mailbox's client list.

If found, return ptr to client_chaln record.

Else, return NULL.

- Add an fsm as a mbx cl lent.

- Remove an fsm from the respective mbx client list.

- Find a mbx (by ptr) on the list kept by the fsm.

- Add a mbx to the 1 1st kept by the fsm.

- Find a mbx (by ptr) on the list kept by the fsm

and remove it from the list.

48 cm_val idate_fsm - val I date the fsm name.

50 cm val idate mbx - val idate the mbx name and size.

UTILS.C

PAGE 1
FLIST (VI . 1/FR) CM

Listed: 26-AUG-1988 16:42:08

52 cm val I date access - val (date the mbx access code.

54 find update rec 55

56

- Look for an update record in the update 1 1st

of this fsm that references mbxhandle. If found,

return pointer, else return NULL.

58 add_update_ree - Add an update record to the list for this fsm.

60 del_update_rec - If this mailbox is on the update list of this

61 fsm (waiting to be read) then delete it.

63 notify cl tents

64

65

66

- Notify all clients on the access list of this

mbx that the mbx has been updated. If the client

already has an update notice for this mbx, do not

make another entry.

68 eiear^declare - If new structures were allocated for this

69 mbx declaration, FREE them and return.

71 cm Ini 72

73

74

75

76

77

78

79

80

8182

- Initialize the variables and data structures

required by the common memory manager. This

routine Is cal led the 1st time a user makes a cm call. This call is triggered because cm_activlty

Is NULL. The application can call cmJnT directly In order to force the initialization at a known point.

This would be desirable, for example, if the

application wanted to change CMDEBUG_LEVEL or CMJaET^STATS. Function can be called multiple times

without detrementa! results (ostensibly, this would

be for the purpose of displaying the library

version number).

84 iog_status - Routine to log cm useage statistics.

86 cmjjet_statusname - Return a pointer to string that gives the status name

87 associated with the status code.

89 */

91 #!nclude «stdlo.h>

92 # include "cmjjlobais.h"

95 « include <stdarg.h> /* as written, this routine is specific to Turbo C V

96 /* 1 1 ! 1 1 1 1 1 i i 1 1 1 1 1 ! 1 1 1

displays var iabie-iength arg 1 1st using fmt

97 * | eprintf j IF level <= DEBUG LEVEL

100 void epr intf ( int level, char *fmt, ...)

101 { vaj ist argDtr;

UTILS.C

PAGE 2
FLIST (VI . 1/FR) CM

Listed: 26-AUG- 1988 16:42:08

103 if (level <= CM_DEBUG_LEVEL) {

104 va_start(argptr, fmt);

105 vprintf(fmt.argptr);

106 va end(argptr);

107 }

108 }

111 112

113

114

115

116

117

/* 1 1 1 1 1 1 1 1 m 1 1 M 1 1 1 M 1 1 1 1 1 1 1

> 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 it 1 1 1 1 1 1

* | cm_f ree_mbx_c I i ent_ 1 1 st | * 1 1 1 1 T ii 1 1 1 1 1 1 1 1 1 1 1 1 1 ii 1 1 1 ii

1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1

*/

FREE the mbx's entire client list

in preparation for deleting the mbx

static void cm_free_mbx_cllent_llst (list)

struct client_chain ‘list;

{ struct cl ient_cha in *tptr;

119 while (tptr - list) ( 120 list= I !st->next;

121 free(tptr);

122 }

123

}

1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1

1 1 1 1 1 1 1 ii 1 1 1 1 1 1 ii 1 1 1 1 1 1 1

cm_free_fsm_mbxj 1st !

1 1 1 1 1 1 1 1 1 1 M i M 1 1 ii 1 1 1 1 1

1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1

129 */

130 stat I c vo I d cm_free_fsrajnbx_ 1

st

131 struct mbx_dec7_chaTn ‘list;

132 { struct mbx dec I chain ‘tptr;

REE the fsm's entire mbx list In preparation for deleting the fsm entry

(list)

126 /*

127 *

128 *

134 while (tptr - list) {

135 llst« I !st->next;

136 free(tptr);

137 }

138 }

141 /* liSi!!ll!l!SI!llll!llll free al I memory a I located to an update 1 1st

142 * | cm_free_update_l 1st | 140 * 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1

1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 11 1

144 */

145 void cm_free_update_l lst(l 1st)

146 struct update list ‘list;

147 {

148 struct updateJist ‘tptr;

150 while (tptr = list) { 151 list = tptr->next;

152 free(tptr);

153 }

UTILS.C

PAGE 3
FLIST (VI . 1/FR) CM

Listed: 26-AUG- 1988 16:42:08

154 }

157

158

159

160

161

162

163

164

/* i!ii!i!Si!iSSSSuSi Check If the fsm is on the era's cl lent 1 1st. * | cmjsmjind S If found, return ptr; else return NULL.

* I I II l.l I I ! I I II I I I I 1 I II I I I I I II I I I I I I I I I t */

static fsmjec ‘cmjsmjind (fsm)

register char *fsm;

{

register fsmjec *tptr;

166 If (tptr * cmjsmj 1st)

167 while (tptr)

168 if (strcmp(fsm,tptr->fsraname) ** 0)

169 return (tptr);

170 else tptr * tptr->next;

171 return (NULL);

172 }

175 /* ii !!!!!!!! !!!!:!:!! Hi Check If the mbx is already in the cm.

176 * i cm_mbx_find j If found, return ptr; else return NULL.

177 * 1 1 1 1 1 1 m in mi i t i i in 1 •• mmmiiiiiiiiiini

178 */

179 static mbxjec ‘cmjnbxJInd (mbxname)

180 char ‘iiibxname;

181 {

182 register mbxjec ‘tptr;

184 If (tptr * cm mbx 1 1st)

185 while (tptr)

186 If (strcmp(mbxname,tptr->mbxnarae) ®» 0)

187 return (tptr);

188 else tptr = tptr->next;

189 return (NULL);

190 }

193 /• i ! i i !!!!!!!!!!!!!!!

Remove a mailbox entry from the cmjnbxJ 1st

194 * | cmjnbx_de I

|

197 static int cmjnbxjjel(entry)

198 mbx rec ‘entry;

199 {

200 mbxjec ‘tptr;

202 free(entry->data); /* free the data mailbox */

203 if (cmjnbxJ 1st entry) { /* if it's the 1st entry, adj ptrs */

204 cm mbx list = entry->next;

UTILS.C

PAGE 4
FLIST (VI . 1/FR) CM

Listed: 26-AUG- 1988 16:42:08

205 free(entry);

206 eprintf(6,

M cmjnbx_del: mbx entry deleted from top of list\n");

207 return;

208 }

209 tptr = cm mbx list; /* look for this entry's predecessor V

210 while (tptr)"

211 if (tptr->next =* entry) { /* found It. adjust the pointer */

212 tptr->next = entry->next;

213 free (entry);

214 eprintf(6,"cm_mbx_del : mbx entry deleted\n");

215 return;

216 ) else tptr = tptr->next;

217 printfCXccm mbx del: FATAL ERROR - entry not found! Call network team.");

218 ex It (0x40); "

219 )

/* lli:;iSII!!Slli!ISI!SI Remove an fsm entry from the cm_fsm_l 1st

* | cm_fsm_de I | * 1 1 1 m 1 1 M i M 1 1 1 1 1 1 1 m i

1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1

V

static int cm_fsm_del(entry)

fsm rec ‘entry;

{

fsm_rec *tptr;

231 cm_f ree_ipdate_ 1 1 st (entry->ipdate_top) ; 232 if (cm_fsm_l 1st — entry) { /* If It's the 1st entry, adj ptrs */

233 cm_fsm_T 1st - entry->next;

234 free (entry);

235 eprintf(6,"cm_fsm_del: fsm entry deleted from top of llst\n");

236 return;

237 }

238 tptr - cm_fsm_list; /* look for this entry's predecessor V

239 while (tptr)

240 if (tptr->next ** entry) { /* found it. adjust the pointer V

241 tptr->next « entry->next;

242 free (entry);

243 eprintf(6,"cm_fsm_del: fsm entry deieted\n");

244 return;

245 } else tptr » tptr->next;

246 printf("2ccm fsm del: FATAL ERROR - entry not foind! Call network team.");

247 ex it (0x40); "

248 }

222

223

224

225

226

227

228

229

251 /* 1 1 1 1 1 1 1 1 ii ii ii 1 1 1 1 1 1

M 1 1 1 1 1 1 1 1 1 1 1 ii 1 1 1 1 1

Find the mbx record associated w/ this mbxhandle

252 * cmjnbxhand 1 e_f 1 nd | Return NULL if not found.

253 * 1 1 M 1 1 1 1 1 ii ii i ii i ii 1

i ii 1 1 1 1 1 1 1 1 1 1 1 ii 1 1 1 1

254 */

255 static mbx rec *cm mbxhandle find (mbxhandle)

UTILS.C

PAGE 5
FLIST (V1.1/FR) CM

Listed: 26-AUG— 1988 16:42:08

256 int mbxhandle;

257 {

258 register mbx_rec *tptr;

260 If (tptr * cmjnbxJ 1st)

261 while (tptr)

262 If (tptr->handle »* mbxhandle)

263 return (tptr);

264 else tptr = tptr->next;

265 return (NULL);

266 }

269 /* j!!I!i!!!! j!! jj!!!!!i! Check If the fsm Is on this mai Ibox's cl lent 1 1st.

270 * ! find mbx client \ If found, return ptr to client chain record,

271 * mSmImTmITmmmmS Else, return NULL.

272 V

273 stat I c struct c 1 1 ent_cha I n *f I ndjnbxjD I Sent ( I ist.fsm)

274 struct cl ient_chaln ‘list;

275 register char *fsm;

276 {

277 struct cl lent^cha in *tptr;

279 if (tptr - list)

280 while (tptr)

281 If (tptr->who «* fsm)

282 return (tptr);

283 else tptr * tptr-»next;

284 return(NULL);

285 }

288

289

290

291

292

293

294

295

296

297

/*

«

*V

ii i n 1 1 i it n i i n n i t iiiiimiiiiimiin

addjnbx_ci lent

I I I I I I I HI ID HI I III

I I I I I II I I I I I I I I I I I I I

Add an fsm as a mbx cl lent.

static int addjnbx_el lent (fsm, o 1 1 ent list, exclusive)

struct cllent_chain **cl lent! 1st;

boolean exclusive;

char *fsm;

{

struct c i I ent_cha I n *tmp_e I i entjec

299 eprintf(7 s "addjT)bx_elient: attempt to add %s\n\fsm);

300 tmp_c! ientjec (struct c! ient_chaln *) mai ioc (s I zeof (struct cl ient_chain));

301 if (ltmp_cTient_rec) return(E_CMJ NSUFFMEM) ; /* verify that mai Ioc worked V

302 tmpjcl ient_rec->who = fsm;

303 tmp_c I i ent_rec->next = *c I i ent list;

304 tmp_c I i ent_rec~>exc i us i ve = exclusive;

305 ‘cllentllst = tmp client rec; 306 returnd CM OK); “

UTILS.C

PAGE 6
FLIST (VI . 1/FR) CM

Listed: 26-AUG- 1 988 16:42:08

307 }

310 /* !!!!!! !i Si !',!!!!!!! i! ! Remove an fsm from the respective mbx cl lent I ist.

311 * | del_mbx_cllent ! OIO * I I I I II iTl I I II I II I I I I I I

1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1

313 */

314 static void del_mbx_cl lent (client, cllentlist, nr_clients)

315 struct client_chain »cl lent, “cllentlist;

316 int *nr_cl ients;

317 { struct client_chain *tptr;

319 eprintf(7,"del_mbx_client: attempt to add %s\n\cl lent->who->fsmname);

320 —(*nr_clients); /* decrement cl lent court */

321 If (client == ‘cllentlist) { /* if It's the 1st entry, adj ptrs */

322 *cl lent 1 1st - cl lent->next;

323 free(cl lent);

324 eprintf(9,"deljnbx_cllent: fsm client entry deleted from top of llst\n");

325 return;

326 ) 327 tptr * ‘cllentlist; /* look for this entry's predecessor */

328 while (tptr)

329 if (tptr->next client) { /* found It. adjust the pointer */

330 tptr->next - cl ient->next;

331 free (cl lent);

332 eprintf(9,"deljnbx_cl lent: fsm client entry deletedNn");

333 return;

334 ) else tptr tptr->next;

335 prlntf("%cdel mbx client: FATAL ERROR - client entry not found! Call network team.");

336 ex It (0x40);

337 )

340

341

342

343

344

345

346

347

348

349

350

351

352

353

/*

*

ii 1 1 1 1 1 1

1 1 1 1 1 1 1 1

1 1 1 1 1 ii 1 1

1 1 1 ii 1 1 1 1

f ind_fsm_mbx

1 1 1 1 1 1 1 1 1 ii 1 1 1 1 ii 1 1

1 1 1 1 1 1ii 1 1 1 1 1 1 1 1 1 1

Find a mbx (by ptr) on the 1 1st kept by the fsm

V

static struct mbx_decl_chain *f ind_fsm_mbx (list, mbx)

struct mbx_decT_chaTn ‘list;

mbx rec *mbx;

{

while (list)

If (I lst->mbx =* mbx)

return(l ist);

else I ist = I ist->next;

return(NULL);

356 /* ! I ! I j ! ! ! 1 1 ! ! ! 1 1 1 1 ! ! ! ! ! Add a mbx to the I ist kept by the fsm

357 • S add fsm mbx j

UTILS.C

PAGE 7
FL I ST (VI . 1 /FR) CM

Listed: 26-AUG-1988 16:42:08

ocq * m i i m i i m i i i i i m i i i i i 330 I I I I I I I I I I I I I I I I I I I I I I 359 */

360 static Int add_fsm_mbx (list, mbx)

361 struct mbxjiec I _cha in ** 1 1 st

362 mbxjec *mbx;

363 { struct mbxjjecljshaln *tptr;

365 if (f lnd_fsmjnbx(* 1 1st , mbx))

366 return (

I jCMjOK) ; /* already exists, don't need to add It */

367 eprintf(7,

M add_fsmjibx: attempt to add %s\n%mbx->mbxname);

368 tptr « (struct mbx dec! chain *) malloc (sizeof (struct mbx decl chain));

369 if (itptr) return(E_CMJNSUFFMEM) ; /* verify that inalloc worked */

370 tptr->mbx = mbx;

371 tptr->next » *1 1st;

372 *1 ist * tptr;

373 returnd CM OK);

374 }

377 /» jllSIS!!!!!!!'!'!!!!! Find a mbx (by ptr) on the I ist kept by the fsn

378 * \ del fsm mbx entry \ and remove It from the list

381 static void del Jsm_mbx_entry (list, mbx)

382 struct mbx_decl_chaln “list;

383 mbx_rec *mbx;

384 { struct mbx decl chain *tptr, *prev!ous;

386 eprintf(7, K dei fsm mbx entry: looking for mbx %s\n\mbx->mbxname);

387 tptr -*l 1st;”

388 previous * HULL;

389 whi le (tptr) {

390 eprintf(9,"del_fsm_mbx_entry: comparing %s\n",tptr">mbX”>mb»iame);

391 if (tptr->mbx »» mbx)

392 if (previous NULL) {

393 *i ist * tptr->next;

394 free (tptr);

395 return;

396 }e!se {

397 previous->next * tptr->next;

398 free (tptr);

399 return;

400 }

401 else {

402 previous = tptr;

403 tptr * tptr->next;

404 }

405 }

406 epr intf(7,"del fsm mbx entry: couldn't find mbx on list\n");

407 }

UTILS.C

PAGE 8
FLIST (VI . 1/FR) CM

Listed: 26-AUG- 1988 16:42:08

410 /* iiiiliii!!!!!!! !!!!!!! val Idate the fsm name

411 * ! cm_val ldate_fsm ! 419 * I I II I l I II l l II II II l I I l l

l l l l I II l l l l l l l l I I I l l l l 413 V

414 int cm_val ldate_fsm(fsm)

415 char * fsm;

416 { int I;

418 I = strlen(fsm);

419 eprintf(9,“cm validate fsm: fsm = \"Xs\\ length « Xd characters^", fsm, I);

420 If ((I > MAXFSMNAMELENGTH) !! (i < 1))

421 return (E CM FSMNAME);

422 returnd CM OK);

423 }

426

427

428

429

430

431

432

433

434

1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1

1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1

cm_val idatejnbx

1 1 M 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1

1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1

validate the mbx name and size

Int cm_val idate_mbx(mbxname,mbxsize)

char * mbxname;

int mbxslze;

{ Int I;

436 i = strlen(mbxname); /* validate mbx name V

437 eprintf(9,"cm validate mbx: mbxname - VXsV, length « Xd charactersNn", mbxname, I);

438 if ((I > MAXbBXNAMELENGTH) !! (i < 1))

439 return (E_CM_MBXNAME);

441 /* validate mbx size - must be greater than 0 bytes long V

442 eprintf(9,"cm_val idatejnbx: mbxslze * %d\n", mbxslze);

443 If (mbxsize < 1)

444 return (E CM MBXSIZE);

445 returnd CM 0K)7

446 }

448 /* !!!! !i ! i !!!!!! j !!!!! Ival Idate the mbx access code

449 * | cm validate access \

452 int cm_val idate_access(mbxaccess)

453 int mbxaccess;

454 {

455 int I;

457 eprintf(9,

u cm validate access: mbxaccess = (hex) Xx\n

M

, mbxaccess);

458 i = mbxaccess’& (CM_READ_ACCE$S | CM_WRITE_ACCESS \ CM_XREAD_ACCESS j CM_XWRITE_ACCESS);

459 if ((mbxaccess — 0) !! (I !« mbxaccess))

UTILS.C

PAGE 9
FLIST (VI . 1/FR)

Listed: 26-AUG- 1 988 16:42:08

CM_UTILS.C

PAGE 10

460

461

462

463

464

465

466

return (E CM MBXACCESS);

If ((mbxaccess I (CM READ ACCESS j return (E CM MBXACCBOTH)

if ((mbxaccess & (CM WRITE ACCESS

return (E CM MBXACCBOTH);

return ( I CM 0K)7

/* unrecognized code V

CM_XREAD^ACCESS) ) — (CM_READ_ACCESS j CM_XREAD_ACCESS))

/* can't request both concurrently V

! CM_XWR I TE_ACCESS) ) — (CM WR ITE ACCESS ! CM_XWRITE^ACCESS))

/* can't request both concurrently *7

469 /* I! ! ! I ! ! 1 1 ! ! S

III! S !

Look for an update record in the update 1 1st

470 * ! f ind_update_rec i of this fsm that references mbxhandle. If found,

471 * !!!!!!!! Si SI! !!!!!!!!! return pointer, else return NULL.

472 »/

473 static struct updatejlst *f I ndjpdate/ec^sm,mbxhandle)

474 int mbxhandle;

475 fsm rec *fsm;

476 {

477 struct updatej 1st *tptr;

479 If (tptr * fsm->update_top) /* a list exists V

480 while (tptr)

481 if (tptr->mbxhandie ** mbxhandle) {

482 eprintf(9,"f lnd_update_rec: FOUND for %s, mbxhandle %d\rf,

483 fsm->fsmname, mbxhandle);

484 return(tptr);

485 }else tptr * tptr->next;

486 eprlntf(9,“f Ind^updatejec: NOT FOUND for %s, mbxhandle Xd\n",

487 fsm->fsmname, mbxhandle);

488 return (NULL);

489 }

492

493

494

495

496

497

498

499

500

/* I S S I S S S S S Si S S S S S ! S S S S I Add an update record to the 1 1st for this fsm

* S add_update_rec ! « imunimmmmi HI II I I III I I III I Ml I I I */

static void add_update_rec( fsra , mbxhand ! e

)

int mbxhandle;

fsm rec *fsm;

{

struct updatejlst *tptr;

502 tptr « (struct update list •) mal loc (slzeof( struct updatej ist));

503 if ( ! tptr ) ( /* verify that malloc worked V

504 printf("%cadd update rec: FATAL ERROR malloc failed. Out of Memory ?”,7);

505 ex it (0x40);

506 }

507 tptr->mbxhand!e = mbxhandle;

508 tptr->next = NULL;

509 if (fsm->>update_bot)

510 fsm->update bot->next tptr; /* adjust NEXT ptr for old BOTTOM V
FLIST (VI . 1/FR) CM

Listed: 26-AUG-1988 16:42:08

511 fsm->update_bot = tptr; /* point to new bottom */

512 if (!fsm->update_top) /* If this is 1st structure in chain

513 fsm->update_top = tptr; /* then set TOP ptr V

514 ++(fsm->nr updates);

515 eprintf(8,“add update rec: update record added to Xs, mbxhandle 2d\n“,

516 fsm->fsmname, tptr->mbxhandle);

517 }

/* !!!!!!!!!!!!!!!!!!!!!! If this ma I Ibox Is on the update 1 1st of this

* i del_update_rec i fsm (waiting to be read) then delete it. * m

it 1 1 1 1m i m 1 1 m 1

M 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1

*/

static void deljipdatej'ec(fsm,mbxhandle)

Int mbxhandle;

fsm_rec *fsm;

{ struct updatejlst *tptr, *t2ptr;

529 if (tptr fsm->update_top) { /* make sure we have a 1 1st */

530 if (tptr->mbxhandle — mbxhandle) { /* Is It at the top of the list V

531 eprintf(8,“del_i|Ddate_rec: deleted from top of update rec list\n");

532 If (fsm->update_top = fsm->update_bot) {

533 fsm->update_top « NULL; /* only 1 entry on the list V

534 fsm->updatejx)t - NULL; /* so adjust bottom ptr too V

535 jelse

536 fsm->update_top « fsm->update_top->next;

537 free(tptr);

538 —(fsm->nr_updates) ; /* decrement update count */

539 return;

540 )

542 whi le(tptr->next)

543 If (tptr->next->mbxhand le ** mbxhandle) {

544 —(fsm->nr_updates); /* decrement update count V

545 t2ptr * tptr->next;

546 tptr->next » tptr->next->next; /* adjust the ptr */

547 free(t2ptr); /* free the update record */

548 if (tptr->next »» fsm->update_bot)

549 fsm->update_bot » tptr;

550 eprlntf(8,"del_update_rec: deleted\n");

551 return;

552 }else tptr = tptr->next;

553 ) 554 }

520

521

522

523

524

525

526

527

i ii 1 1 1 m 1 1 1 1 1 ii 1 1 1 1 1

1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1

not I fy_c I ients \

1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1

M 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1

560 *

561 */

557 /

558

559

Notify all clients on the access list of this

mbx that the mbx has been updated. If the client

already has an update notice for this mbx, do not

make another entry.

UTILS.C

PAGE 1
FL I ST (VI . 1 /FR) CM

Listed: 26-AUG- 1988 16:42:08

562 static void not ify_cl lents(cl ientl 1st, mbxhandle)

563 struct cl ient_cha in *cl Ientl 1st;

564 int mbxhandle;

565 {

566 eprlntf (9, "notify clients: for mbxhandle Xd\n", mbxhandle);

567 if (cl ientl ist) ” /* client list exists ? V

568 while (cl ientl Ist) {

569 if (If ind_update_rec(cl Ientl ist->who t mbxhandle)) /* update exist ? V

570 add_update_rec(cl ientl I st->who, mbxhandle); /* NO - add it */

571 cl ientTlst « cl ientl ist->next; /* check next client V

572 }

573 }

1 1 ! ! S 1 1 1 ! ! S ! ! !1 1 1 1 ! I S If new structures were a I located for this

\ clearjJeclare \ mbx declaration, FREE them and return.

1 1 1 m 1 1 1 mTi 1 1 1 u 1 1 1 i i

1 1 1 1 m m m n m 1 1 1 1 1 m i 579 V

580 static int elear_deciare (newjsm, newjnbx, tmp fsia rec, tmpjnbxjee, err code)

581 boolean newjsm, newjnbx;

582 fsmjec *tmpjfsm_rec;

583 mbxjee *tmpjnbx_rec;

584 int err code;

585 {

586 if (newjsm) { /* FREE the fsm rec */

587 eprintf(6/ciear_declare: free the fsm record \n");

588 if (tmpjsra_rec->read.mbxjist) { /* FREE mbx lists first V

589 eprintf(6,“clear_declare: free fsm reader listNn");

590 cm free fsm mbx 7ist(tmp fsm rec->read.mbx list);

591 }

592 If (tmp_fsm_rec->wr!te.mbxj ist) {

593 eprintf(6,“clearjiec!are: free fsm writer listNn");

594 cm free fsm mbx Tlst(tmp fsm rec->write.mbx list);

595 }

596 free(tmp fsm rec);

597 }

598 if (newjnbx) {

599 eprlntf(6, "clearjjeciare: free the mbx record \n");

600 if (tmp_mbx_rec->data) { /* FREE the data mbx, too */

601 eprlntf(6,"clear_declare: free data mbx\n“);

602 free(tmp mbx rec->data);

603 )

604 if (tmpjnbx_rec-> reader I ist) { /* FREE the client lists first */

605 eprintf(6,"clear_dec!are: free mbx reader I lst\n“);

606 cm free mbx client I ist(tmp mbx rec->readerl 1st);

607 }

608 if (tmpjnbx_rec->writerl ist) {

609 eprintf (6, "clearjjeciare: free mbx writer! IstNn");

610 cm free mbx client I ist(tmp mbx rec->wr iter I ist)

611 }

612 free(tmp mbx rec);

576 /*

577 *

578 *

UTILS.C

PAGE 12
FLIST (VI . 1/FR)

Listed: 26-AUG- 1 988 16:42:08

CM_JJT I LS . C

PAGE 13

613 —cm mbxhandle;

614 }

615 return (err code);

616 )

/

1 1 1 1 1 1 1 m m i

1 1 1 1 1 1 1 1 1 1 1

cmjni

1 1 1 1 1 1 1 1 1 1 1

1 1 1 1 1 1 1 1 1 1 1

Initialize the variables and data structures required

by the common memory manager. This routine is called

the 1st time a user makes a cm call. This is triggered

because cm activity — NULL;

The following values, when assigned to CM_DEBUG_LEVEL, result In the

display of debugging data corresponding to that level via routine eprlntf.

The debugging levels "build" upon each other. That is, selecting a debug level also displays those levels below it (ie, those that have

a lower debug level number).

0 - no debugging data Is displayed

1 - display the common memory library version (complied Into lib)

2 -

3 -

4

- 5 - when a mbx is written or read

6 - when fsm/mbx are added/deleted by cmm, or when cm_declare failed.

7 - when an fsm/mbx client is added/deleted

8 - when an fsm has update records added/deleted

9 - everything (includes 0-8 and more)

V

void cm lnl()

/* The Initial global value of CM_DEBUG_LEVEL is set to -1 in file cm_globa.h.

If the application program changes the value to be >» 0, then cmjni will not

change it again. If It Is still <0, cm ini will turn off debugging satements */

{ if (CM_DEBUG_LEVEL < 0) CM_DEBUG_LEVEL - 0; eprintf(1, "cmjni: using common memory library version %s\n“,CM_VERSION);

if (cm_actlvlty) /* ck if we've been here before V

eprlntf (9, "cmjni: function called again AFTER init already performed\n“);

else ( eprlntf (9, "cmjni: init In progressNn");

cm_activlty = (cm_actlvlty_stats *) malloc (slzeof(cm_act!vity_stats));

cm_clients = (cm_cl lent_stats *) malloc (sizeof(cm_cl!ent_stats));

if ((Icm activity) || (Icm clients)) { /* verify that malloc worked V

prlntf(“%ccm Ini: FATAL ERROR malloc failed. Out of Memory ?",7);

657 exit(0x40); ”

658 ) 659 be I r (cm_act I v I ty , s I zeof (cm_act I v I ty_stats ) )

660 bclr(cm cl ients,sizeof(cm client stats));

661

662 }

}
FL I ST (VI . 1 /FR)

Listed: 26-AUG- 1 988 16:42:08

CMJJTILS.C

PAGE 14

665

666

667

668

669

670

671

672

673

674

675

676

677

678

679

680

/* 1 1 S ! i S S ! S S S S S S Rout ine to log cm useage stat 1st ics.

* i log_status ! * 1 1 1 1 1 M 1 1 1 1 1 1

1 1 1 1 1 1 1 1 1 1 1 1 1

V

static void log_status(func,fsm, mbx)

base_stats *func;

char *fsm, *mbx;

( if (CM_GET_STAT$) {

eprIntf(9,"log_status: in progress'^")

strcpy(func->fsm,fsm);

strcpy(func->mbx,mbx)

time(&func->when);

++func->nr times;

}

}

/* save the fsm name V

/* save the mbx name V

/* note the time and date •/

/* increment nr times this function called */

683 /* S | II i J S ! \ S

*

i ' S S S ' S S IS return ptr t© string that gives the status name

684 * | cmjjet_statusname j associated with the status code.

687 char *cm_get_statusname (code)

688 int code;

689 { char * status;

691 switch (code) {

692 case I CM OK : status

693 case fCMlBXACTV : status

694 case fCM~DUPkBX : status

695 case l“CM”MOREDATA : status

696 /* easel CM FATALERR : V

697 case E_CM_INSUFFMEM : status

698 break;

699 case E CM M3XERR : status

700 case E”CM~fc8XN0READ ; status

70T case e”cM~MBXNOXREAD : status

702 case e”cm“^BXNOWR ITE : status

703 case E~Cm1bXN0XWRITE : status

704 case E~CM~fc£X$IZE : status

705 case eImIbXACCESS : status

706 Case E~Cm1bXACCB0TH : status

707 case eImIbXNAME : status

708 case e“cM~MBXNOTDECL : status

709 case E CM_FSMERR : status

710 case E”CM”FSMNAME : status

711 case E~CM_FSMNOT I NCM : status

712 default : status

713 }

714 return (status);

"I CM OK"; break;

-|”cm“mBXACTV"; break;

"fCMluPteX"; break;

"l”CM~MOREDATA"; break;

"E_CM_FATALERR or E_CMJ NSUFFMEM"

"E CM MBXERR"; break;

“E~CM~MBXNOREAD" ; break;

"E~CM~MBXNOXREAD " ; break;

"E~CM~MBXNOWR ITE"; break;

“ e”cM~MBXNOXWR ITE"; break;

"E”cm”mBXSIZE"; break;

“E~CM~MBXACCESS" ; break;

" E°CM~MBXACCBGTH " ; break;

m e“cm”mBXNAME"; break;

" E~CM~MBXNOTDECL ” ; break;

"E~CM~FSMERR

M

; break;

"E~CM~FSMNAME " ; break;

"E”CM”FSMNOTINCM“; break;

"unknown code"; break;
FLIST (VI . 1/FR)

Listed: 26-AUG- 1988 16:42:08

715 }

CMJJT I LS .

PAGE 15
iHB

f

amw

afel:

mjMm

Hf§£|' «IBi

anpi HI

^P§^<I' $

* Bp
FLIST (VI . 1/FR)

Listed: 26—AUG- 1988 16:42:57

1o

/*

* sfuncs.c - miscellaneous functions

L3

A

** asci idump(b,n) dump n bytes starting at b, in ascii.

n

5

e

*

* bclr(b,n) clears (sets - 0) n bytes starting at address b.

0

7

8

9

*

* bcpy(s,t,n) copies n bytes from s to t.

* binstr(n.str) convert byte to binary representation In string str.

10 *

11 * cvtup(c) converts a lowercase ascii string to upper.

12 *

13 * hexdump(b.n) dump n bytes starting at b, in hex.

14 *

15 * is_asc 11(c) returns TRUE if c Is a printable ascii character.

16 *

17 * pause(fmt, ...) routine works like "printf", and accepts a variable18 * length arg list after fmt. After It displays the

19 * user-specified data. It displays "Press any character

20 * to continue...", waits for a kbd entry, then

21 * outputs <CRLF> and returns.

22 V

25 /* dlsplaynbytes In ascii, starting w/ address

26 * ! asclidump | ' i' columns per line.

27 * It II 1 1 1 i II II 1 1 1 M It 1 II

II 1 II 1 1 1 II 1 1 1 II 1 1 1 1 1 II 28 V

29 void asci i&imp(b,n)

30 register char *b;

31 register Int n; 32 { register Int i - 20;

34 whi le (n—) {

35 If ((*b > Qxlf ) && (*b < 0x7f))

36 printf ("%3c",*b++);

37 else printf (" 202x", Oxff & *b++);

38 If (_j o) {

39 printf ("\n") ; 40 I - 20;

41 }

42 }

43 if (1 < 20) printf("\n") ; 44 }

47 /* 1 1 1 ii 1 1 1 1 1 1 1 1 1 1 1 1 1

' 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1

111 set n bytes = 0, starting w/ address b

48 * i bclr i

i 49 * 1 1 1 1 M 1 1 1 m 1 1 1 1 1 1 1

1 1 1 1 1 1 1 1 ii 1 1 1 1 1 1 1 1

1 1

1 1 50 V

51 void bclr(b, n)

SFUNCS.C

PAGE 1
FL I ST (VI . 1 /FR)

Listed: 26-AUG- 1 988 16:42:57

52 register char *b;

53 register int n; 54 {

55 while (n—) *b++ • H o

56 }

59 /* 1 1 1 1 1 1 1 M 1 1 m 1

1 1 M i M 1 1 1 1 1 1 1

! | ! |

copy n bytes from s to t 60 * bcpy i 61 * M 1 1 1 1 u 1 1 1 1 1 1

1 1 1 1 1 1 1 1 1 M 1 1 1

i i i i i

i i i i i 62 */

63 void bcpy(s, t, n)

64 register char *s, *t;

65 register int n; 66 C 67 whi le (n—) *t++ *S++;

68 }

71 /* 1 1 M 1 1 1 1 1 1 1 1 1 1

• 1 1 1 1 1 1 u i u 1 1

! 1 1 j convert byte n to Its binary representation

72 * binstr i in string str. Return ptr to str In case

73 as 1 1 1 1 1 1 1 1 1 1 1 1 1 1

1 1 1 1 1 1 1 1 1 1 1 1 1 1

! i i S

calier wants to display it as part of a printf.

74 * The user-allocated space for str must be at least

75 * 9 characters long, 8 for the binary representation

76 * and 1 for the trailing NULL;

77 »/

78 char * blnstr(n.str)

79 unsigned char n; 80 char *$tr; /* must be at least 9 bytes long s

81 { int 1;

83 for (1 * 0; 1 < 8 ; I++) C 84 str[l] * (n & 0x80) ?

'1' : 'O';

85 n * n « 1; 86 }

87 str[8] - 0; /* null - terminate the string V

88 return (str);

89 }

92 /* 1 1 1 1 1 1 1 M 1 1 1 1 1 1

1 1 1 1 1 1 1 1 g 1 1 1 1 1 1Hi j j| convert a lowercase ASCII string to uppercase.

93 *

! cvtup i

i 94 * 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1

1 1 1 1 1 1 1 1 1 1 1 1 M 1

1 1 1 1 1

1 1 1 1 1

95 V

96 void cvtup (s)

97 register char *s;

98 ( 99 while (*s) {

100 if (*s >« 'a' && *s <= 'z') *s - 'a' - 'A';

101 S++;

102

SFUNCS.C

PAGE 2
FLIST (VI . 1/FR)

Listed: 26-AUG- 1 988 16:42:57

SFUNCS.C

PAGE 3

103 }

106 /* !!! 107 * ! 108 * HI

109 */

i ii 1 1 1 1 1 1 1 1 1 m m 1 1 ii i

1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1

hexdump

display n bytes In hex, starting w/ address b.

'I' columns per line.

1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 ii

1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1

110 void hexdump(b,n)

111 char *b;

112 int n ; 113 { int group, I, max;

114 int max_perj ine - 15;

115 Int group_s7ze = 5;

117 while (n) {

118 max = max_per_l ine;

119 If (max > n) max « n; 120 group - group_slze;

121 for (1=1; I <= max; i++) {

122 prlntf (" %02x",*b++ & Oxff);

123 If (1-groiD) {

124 prlntf (" “);

125 group = group size;

126 }

127 }

128 if (i <« max_per_l Ine)

129 for (1=7; i <« maxjjerJ Ine; I++) {

130 pr intf

( " "); /* space over to ascii field V

131 if (I —group) {

132 prlntf (“ ");

133 group » group size;

134 }

135 }

136 printf(“ "); /* gap between hex and ascii areas */

137 b — max; /* point to start of section V

138 for (1=1; I <= max; I++) {

139 printf(“Xc\ is ascii(*b) ? *b : 5);

140 b++;

141 If (I—group) {

142 prlntf (“2c",176) ; 143 group = grotp size;

144 }

145 )

146 printf(“\n“);

147 n - max;

148

149 }

152 /* : ! ;!!;!!;!!!; j !!!!!! j

returns TRUE if c is a printable asci i character.

153 * ! is ascii !
FLIST (VI . 1/FR)

Listed: 26-AUG- 1988 16:42:57

156 Int ls_ascii(c)

157 char c; 158 {

159 If ((c > Oxlf) && (c < 0x7f))

160 return (1);

161 return (0);

162 }

164 include <stdio.h>

165 #include <stdarg.h>

1 CO /* II II I II II I I I I I I II I I I I I

I OD t I I I I 1 1 I I I I 1 1 1 1 1 I I 1 1 I I I 167 * | pause i ICO * I I I I II I I I I I I I I I I I I I I I I 100 I I I I I I I I I I I I I M M I I I I I 169 *

170 void pause (char •fmt, ...)

171 { vaj 1st argptr;

/* as written, this routine Is specific to Turbo C V

displays variable- length arg list using fmt. Then,

Tress any character to continue..." and waits for

kbd Input. Then echoes <CRLF» and returns. User

msg string can have format Ctrl chars in it. V

173 va^start (argptr, fmt);

174 vprintf (fmt, argptr);

175 va_end(argptr);

176 prlntf ("Press any character to continue... ");

177 getch();

178 prlntf ("\n");

179 }

SFUNCS.C

PAGE 4
Common Memory for the PC

AMRF

cm

cmm

common

common

DOS

finite

fsm

global

local

GLOSSARY

- acronym, refers to the Automated Manufacturing

Research Facility of the National Bureau of Standards.

- abbreviation for "common memory". See also common

memory.

- abbreviation for "common memory manager" . See also

common memory manager.

memory - a term used to generically identify both local

and global common memory. See also local common

memory and global common memory.

memory manager - collection of functions that establish

the mailboxes on the local host and manage associated

data structures to assure and provide proper access to

them. The common memory manager also gathers and

provides utilization statistics.

- abbreviation for "Disk Operating System", a singleuser operating system developed by Microsoft

Corporation for use with the IBM PC class of machine.

It is marketed by various companies under the names PC

DOS and MS DOS.

state machine - a term assigned to user application

programs that have a finite number of clearly defined

processing states. Examples of such states are: data

acquisition, data reduction, and data reporting. In

the context of this documentation, "fsm" is intended

to mean "user application program"

- abbreviation for "finite state machine". See also

finite state machine.

common memory - two or more local common memories combine

to form a global common memory. This is accomplished

with the introduction of a network interface process

(NIP) at each computer system that has a local common

memory. The NIP becomes another client of its local

common memory with all implied READ/WRITE privileges.

NIPs exchange common memory mailgrams with each other

using network services, propagating these mailgrams

globally and creating the global common memory.

common memory - a contiguous area of physical memory

accessible to two or more distinct processes within a

single computer system. This physical memory is

GLOSSARY - 1
Common Memory for the PC

divided into a collection of READ and WRITE mailbox

areas. The data in these areas, called mailgrams, is

available to all other applications on the computer

system.

mailbox - a contiguous area of high-speed memory assigned and

managed by the common memory manager. Messages

(called mailgrams) can be placed into a mailbox by one

or more writer applications and copied from the

mailbox by one or more reader applications.

mailgram - term used to identify the contents of a mailbox. That

is, a collection of contiguous bytes stored in a

mailbox. The data representation (binary, ASCII,

etc.) for mailgrams is determined by the application

process

- abbreviation for "mailbox". See also mailbox.

- acronym, refers to the National Bureau of Standards,

located in Gaithersburg, Maryland.

- abbreviation for "personal computer". This term is

used to identify all classes of personal computers

that are compatible with the IBM PC and use the DOS

operating system.

- term used to identify a user application program. It

is used interchangably with "fsm".

mbx

NBS

PC

process

GLOSSARY - 2
Common Memory for the PC

LIST OF REFERENCES

[1] Kernighan, Brian W. , Ritchie, Dennis M., THE C PROGRAMMING

LANGUAGE , Prentice-Hall, Inc., 1978.

[2] TURBO C USER'S GUIDE , Borland International, 1987.

[3] TURBO C REFERENCE GUIDE , Borland International, 1987.

[4] Holt, R. C. , Graham, G. S., Lazowska, E. D., and Scott,

M. A., Structured Concurrent Programming with Operating

Systems Applications , Addison-Wesley Publishing Company,

Reading, MA, 1978, p25.

[5] Barbera, A. J., Fitzgerald, M. L. , Albus, J. S., "Concepts

for a Real-Time Sensory Interactive Control System

Architecture", Procedings of the Fourteenth Southeastern

Symposium on System Theory, April 1982, pp 121-126.

[6] Furlani, C. , Kent, E., Bloom, H. , McLean, C., "The Automated

Manufacturing Research Facility of the National Bureau of

Standards", Proceedings of the Summer Simulation Conference,

Vancouver, B.C., Canada, July 1983.

[7] Rybczynski, S., et.al., "AMRF Network Communications", NBSIR-88-3816, June 1988, 206 pp.

[8] Barbera, A. J., Fitzgerald, M. L., Albus, J. S., and Haynes,

L. J., "RCS: The NBS Real-Time Robot Control System",

Proceedings of the Robots VIII Conference, Detroit,

Michigan, June 1984.

[9] Libes, D., "User-Level Shared Variables", Tenth USENIX

Conference Proceedings, Summer 1985.

[ 10 ] Libes, D., "Experiences with a Communications Paradigm:

Common Memory", in preparation.

REFERENCE 1
.
NBS-T14A (rev. 2»6C

U.S. DEPT. OF COMM.

BIBLIOGRAPHIC DATA

SHEET (See instructions)

1. PUBLICATION OR

REPORT NO.

NISTIR 88^3838

3. Publication Date

AUGUST 1988

4. TITLE AND SUBTITLE

Common Memory for the Personal Computer

5. AUTHOR(S)

Rybczynski, S.

6. PERFORMING ORGANIZATION (If joint or other than N BS, see instructions) 7. Contract/Grant No.

NATIONAL BUREAU OF STANDARDS -

U.S. DEPARTMENT OF COMMERCE

GAITHERSBURG, MD 20899

9.

SPONSORING ORGANIZATION NAME AND COMPLETE ADDRESS (Street. City, State, ZIP)

. Type of Report & Period Covered

10.

SUPPLEMENTARY NOTES

Ha Document describes a computer program; SF-185, FIPS Software Summary, is attached.

11.

ABSTRACT (A 200-word or less factual summary of most significant information. If document includes a significant

bibliography or literature survey, mention it here)

The Automated Manufacturing Research Facility (AMRF) at the National Bureau of

Standards is using an architecture called "common memory" (also known as shared

memory) for interprocess communication. This document describes the shared memory

concept and defines the shared memory architecture as implemented on the IBM Personal

Computer (or compatible) using the DOS operating system. A complete shared memory

software library has been written using the C programming language to maximize

portability to other systems. A sample program demonstrating the use of the

common memory environment is included in the software ddstribution.

12. KEY WORDS (Six to twelve entries ; alphabetical order; capitalize only proper names; and separate key words by semicolons)

AMRF; common memory; communications; shared memory

13. availability 14. NO. OF

| X 1 Unlimited

1 1 For Official Distribution. Do Not Release to NTIS

PRINTED PAGES

161

1 Order From Superintendent of Documents, U.S. Government Printing Office, Washington, D.C.

20402. 15. Price

[~^1 Order From National Technical Information Service (NTIS), Springfield, VA. 22161 $18.95

U S COMM* D C 6043"P 80