• Keine Ergebnisse gefunden

Registering Request Codes

Im Dokument Standards Programming (Seite 133-142)

There are two ways to obtain registered request codes in the A and B ranges; by FAX or by telephone.

When you register request codes, you ask for a certain quantity of them, and Technical Support assigns the numbers for you.

By Telephone Time (or Pacific Daylight Time in the Summer months).

8-4 eTOS/Open Programming Practices and Standards - Part I

Ask for the CTOS/BTOS Technical Support Department.

By FAX

To register request codes by FAX, send your FAX to the following United States telephone number:

(408) 434-2131

Address your FAX to "CTOS/BTOS Request Codes." If you fail to address your FAX to "CTOS/BTOS Request Codes" it may be misrouted.

The FAX number is available 24 hours a day.

All FAXed requests to register request codes must include the following information:

• Your name. This consists of your company name and the name of a person who can be contacted if questions arise about your request.

You should also include a telephone number and a FAX number where the contact person can be reached.

• The total number of request codes WITH a procedural interface that you need.

• The total number of request codes WITHOUT a procedural interface that you need.

• A full description of the request block for each request you want to register. See Table 8-1 for the format of a request block.

Do not fill in the rqCode field.

Technical Support will notify you which request code numbers they have assigned to you as soon as possible after receiving your FAX.

Conserving Request Codes and Memory

Request codes are a finite resource. They should not be wasted. In addition, efficient use of request codes has a direct relation to the size of the operating system.

Writing Request-Based System Services 8-5

Conserving Memory with Efficient Request Code Use

CTOS maintains a table in memory for each request code level. This table contains entries for all requests in that level, up to the number of the highest one currently defined. Even if a request code number is undefined, CTOS reserves a slot for it if any request code with a larger number is defined.

For example, assume that on a particular workstation the highest currently-defined request code in level E is OE187h, and you add a new ,request code as number OEFOOh. The operating system must now reserve table entries for all the request codes between OE187h and OEFOOh. Each table entry requires 8 bytes, which in this case adds up to' a lot of wasted memory.

This is one reason Technical Support assigns request codes in the A and B levels. By assigning request codes incrementally, they can keep the number of wasted request table slots to a minimum.

Conserving Request Code Numbers

Use the following techniques to keep the number of request codes needed by your system services to a minimum:

1. When several service functions require similar parameters, add a

"CaseValue" field and use a single request code for all of them.

2. Use the same request for Termination, Abort and Swapping requests.

The three can be distinguished by the contents of the request block.

For more information on these requests, see "Termination and Abort Request" and "Swapping Requests" later in this chapter.

Efficient use of request codes may not be necessary if you are writing a system service purely for your own use. However, if you ever plan to distribute it or to sell it, both your customers and the operating system developers will appreciate your efforts.

8-6 eTaS/Open Programming Practices and Standards - Part I

Operations Performed by a System Service for Applications

A request-based system service performs functions for its client programs.

The function a system service performs can be anything at all, but most often a system service controls access to a shared resource. For example, the queue manager is a system service.

Server/Client Communication

The service and its client communicate using two kernel primitives, Request and Respond. The client uses the Request primitive to send a request block to the system service. The service processes the request, then uses the Respond primitive to send the same request block back to the client. The service sends the request block to the exchange specified by the client in the response exchange field of the request block.

The client can issue the Request primitive directly, or it can use a request procedural interface for the request. If the client uses the Request primitive, the client must build the request block itself. If the client uses the request procedural interface for a request, the operating system builds the request block for the client. Most clients use the request procedural interface.

When the operating system detects that a Request primitive was issued (either directly or through a procedural interface), the operating system kernel checks the request code in the client's request block. It then uses the request code as an index into its request routing table, which contains the exchange number of the service that serves each valid request code.

The operating system looks up the exchange at which the request is served, then sends the address of the request block to that exchange.

When the system service receives the request block's address, it first checks the contents of the request block. If the information is valid, the service performs the requested service for the client, and fills in any response information in the request block. In addition, the service enters a value of zero (ercOK) in the status code field of the request block. If the service encounters an error, or if the request block is not valid, the service enters the appropriate error code in the status code field of the request block.

Writing Request-Based System Services 8-7

Finally, the service responds to the client by calling the Respond primitive. The operating system then routes the response back to the client's exchange, where the client has been waiting for it.

The Server/Client Relationship

When a server provides a service to a client, the two establish a relationship between them. This relationship may last only for the time it takes to respond to a single request, or it may last for a longer term.

Much of the discussion in the following sections treats events differently depending on how they make use of this client/server relationship.

Most of the time, the client establishes a long-term relationship with the server, so that the two can exchange a series of requests and responses.

A typical example of this is reading a sequential file. All the read operations affect the same file, and each one depends on the successful completion of all the previous ones. In such cases, the service must remember not only which file is being read, but also who the client is, in order to close that file if the client terminates abnormally.

This kind of long-term relationship is called a connection. When a client needs to use a service over a period of time, the client must first establish a connection, then use that connection ina series of requests. Then, when it is finished, it must destroy the connection. Anyone connection links one client program to one system service. Clients may have several simultaneous connections to the same or to different services, and vice versa. Each connection, however, is independent of all other connections.

Connections are not peer-to-peer. The client always initiates each communication, and the service replies to it. These roles apply to only one particular connection, however. A given program may act as the server on a connection to one program and as the client on a connection to another program.

Connection Establishment

To establish a connection, the client submits a request to the server. This request must identify which system service the client wants to use. This can be done explicitly or by default. In most cases, the client also

8-8 eTOS/Open Programming Practices and Standards - Part I

identifies a specific resource that it wishes to access. The identification of value as the one returned when the connection was opened.

Listing 8-1 shows how a system service might handle a connection opening

Writing Request-Based System Services 8-9

/* put client's usernum in the handle array at */

/* position wHandle * /

rgHandles[wHandle] = pRq->RqHead.userNum;

/* return ercOK and increment connection count */

pRq->RqHead.ercRet = 0;

cOpenConnections++;

}

Respond(pRq);

}

Listing 8-1. An Open Connection Request

A Note About Handles

As mentioned above, all handles are treated as file handles, which are 16-bit numbers. The top four bits of the handle are used by the operating system for routing, leaving 12 bits for the service to use. The meaning of the top four bits (bits 12 to 15) are listed below.

• Bit 12. Unused. Should always be O.

• Bits 13 and 14. Can be set by the system service to indicate that the service resides on the master.

• Bit 15. Set by network software to indicate that the service resides on a remote network node.

Most system services can simply set all four bits to zero, and let the operating system take care of the routing. However, there is one special case for cluster routing.

If the same system service may be installed on both a cluster workstation and the master, the operating system on the cluster workstation must be able to identify which handles belong to the service on the master.

To accomplish this, the system service on the master should set bits 13 and/or 14 in its handles, and the service on the cluster workstation should leave them both unset. The following two code fragments show how a service can determine whether it resides on a master workstation, then set the appropriate bits.

8-10 eTOS/Open Programming Practices and Standards - Part I

The first determines whether a program resides on the master, and sets a flag accordingly. The second sets the appropriate bits in the handle.

/* Get the system config. block structure */

CheckErc(GetpStructure( Ox2C8 ,0, &pMySysConfigRet»;

/* check byte at offset 33, clusterconfig byte */

if(pMySysConfigRet->ClusterConfiguration

==

2) fMasterOS TRUE;

else

fMasterOS

=

FALSE;

if(fMasterOs

==

TRUE)

/* OR the handle with Ox6000 to set bits 13 and 14 */

wHandle

=

wHandle

I

Ox6000;

/* put the handle number in returned handle field */

*

(pRq->pHandleRet)

=

wHandle;

The Real Work

Once the connection is established, the client and server use requests to manipulate the resource that was allocated for the connection. Typically these requests perform read, write andlor control operations. The requests are guaranteed to be delivered to the server in the order in which they were sent. The server can respond to them in any order, however.

Connection-oriented requests do not identify the server or the resource they affect. They must specify the connection handle instead.

If a request is routed to a remote processor, it cannot exceed 2.SK bytes in size. If a request, such as a disk read, requires more than 2.SK of returned data, the operating system takes special action. The client still issues only a single request, but the operating system breaks it up. The result is that the server receives several separate requests, each for less than 2.SK of data. Then, the operating system collects the server's responses into a single response to match the client's single request.

The only difficulty arises if errors occur on more than one of the server's requests. The server can return one error code on each, but the client can only receive one error code, because it only issued one request. If this happens, the operating system returns the numerically highest error code. For this reason, more severe error codes should be assigned higher numbers.

Writing Request-Based System Services 8~ 11

Listing 8-2 shows a function that returns a string of data in response to a request. The client passes a valid connection handle, the address and size of a buffer, and the address of a variable in which the server returns the actual size of the returned string.

void ProcessDataRequest(DataRqType *pRq) [

Word i=O;

/* check for valid handle */

if(pRq->RqHead.userNum != rgHandles[(pRq->wHandle)l ) [ pRq->RqHead.ercRet = erclnvalidHandle;

TerminatelfErcNotOk(Respond(pRq), (RqHeaderType *) pRq) ;

return;

}

/* calculate the maximum string size */

if(pRq->cbDataRet

<

srgMsgRet) i pRq->cbDataRet;

else

i = srgMsgRet;

/* put the message and the size in the user's buffer */

memcpy(pRq->pbDataRet, &rgMsgRet, i);

*«Word *)(pRq->psDataRet» = i;

/* respond to the request */

pRq->RqHead.ercRet = 0;

TerminatelfErcNotOk(Respond(pRq), (RqHeaderType *) pRq);

}

Listing 8-2. Processing a Data Request

Connection Termination

When a client is finished with a connection, it should request the server to terminate the session. This type of request is generally called a close request. A close request asks the server to release any resources associated with a given connection handle and to terminate the connection with the client who owns that handle.

When it receives a close request, the server must first reply to any outstanding requests on that connection. It can then reply to the close request and deallocate any resources associated with the connection.

8-12 eTOS/Open Programming Practices and Standards - Part I

/* Close connection procedure. Assumes that the */

/* service has already served any outstanding requests */

void CloseConnection(CloseRqType *pRq) (

/* if the user number matches the value in the array */

/* of handles (if the handle is valid) */

if(rgHandles[pRq-)wHandle] == pRq-)RqHead.userNum) ( /* reset the handle and decrement the connection */

/* count */

rgHandles[pRq-)wHandle] = 0;

cOpenConnections--;

pRq-)RqHead.ercRet = 0;

)

/* if the user number doesn't match rgHandles */

else

pRq-)RqHead.ercRet = erclnvalidHandle;

Respond(pRq);

}

Listing 8-3. A Close Connection Request

Connectionless Requests

Short term relationships can be handled by connectionless requests. A connectionless request can be used whenever the execution of the request is independent of all previous and future requests. This means that the server does not need to "remember" anything about the client after it has responded to the request. Connectionless requests are used most often for status requests, configuration updates, and deinstallation requests.

Operations Performed

by

a System Service for the

Im Dokument Standards Programming (Seite 133-142)