Jump to content United States-English
HP.com Home Products and Services Support and Drivers Solutions How to Buy
» Contact HP
More options
HP.com home
HP 9000 Networking: HP FTAM/9000 Programmer's Guide > Chapter 4 Using Support Functions

Responding to Asynchronous Calls

» 

Technical documentation

Complete book in PDF
» Feedback
Content starts here

 » Table of Contents

 » Glossary

 » Index

The MAP 3.0 Event Management interface plays a central role in your use of asynchronous calls to FTAM functions.

It is common to have multiple asynchronous function calls outstanding. As responses to these calls come in, the FTAM Service Provider Process (SPP) queues them. The Event Management interface takes the first response off this queue and returns it to the caller as a MAP 3.0 event. At the same time, the Event Management interface updates the called function's inout DCB to show the outcome of the asynchronous call.

The FTAM/9000 implementation of MAP 3.0 Event Management consists of three functions, each used under slightly different circumstances. The functions are:

  • em_wait()

  • em_hp_select()

  • em_hp_sigio()

Whenever possible, use only em_wait() to wait for and obtain MAP events. Since em_wait() is the only one of the three defined by the MAP 3.0 specification, using it eases porting to non-HP platforms. However, em_wait() is also very limited. Sometimes, you may have no alternative but to use one or both proprietary functions instead of or in addition to em_wait().

Following are some guidelines for each of the three event management functions.

When to Use em_wait()

The em_wait() function enables you to suspend application processing until a MAP event occurs. However, em_wait() does not provide for waiting on any non-MAP events.

Use em_wait() when your application needs to wait exclusively on MAP 3.0 events. For example, if your application is a daemon process which interacts only with the OSI network via FTAM protocols.

When to Use em_hp_select()

The em_hp_select() function is a Hewlett-Packard proprietary extension to the MAP 3.0 specification. It can be regarded as a hybrid of the MAP 3.0 em_wait() function and the HP-UX select() system call. It is located in the common MAP library (libmap.a).

Use em_hp_select() instead of em_wait() when your application needs to wait on MAP events, plus non-MAP events that can be represented by a file descriptor and waited on via the HP-UX select() system call. This may be true if your application is interactive (for example, using asynchronous input from Terminal I/O or the X11 Window system). It also may be true if your application needs to communicate with other processes via named pipes or domain sockets as well as perform FTAM operations over the OSI network.

In addition, use em_hp_select() instead of em_wait() if your application would otherwise need em_wait() to return when interrupted by a signal. The em_hp_select() function does not return by itself when interrupted by a signal, but techniques exist to simulate this behavior. See the section on handling signal interrupts with em_hp_select().

When to Use em_hp_sigio()

The em_hp_sigio() function is another Hewlett-Packard proprietary extension in the common MAP library (libmap.a). It enables the Event Management interface to notify your application via the SIGIO signal when there is a MAP 3.0 event pending. However, em_hp_sigio() does not return any MAP events itself. Therefore, it should complement your use of em_wait() or em_hp_select().

Use em_hp_sigio() along with em_wait() or em_hp_select() when your application needs to control the dispatch of MAP and non-MAP components by using signals and/or semaphores to indicate when a particular component has work to do. This is often necessary when porting applications from other operating systems such as AT& T's System V Unix or DEC's VMS.

Using em_wait()

#include %</opt/ftam/include/map.h>
Return_code
em_wait (timeout, return_event_name, result)
Em_t timeout;
Local_event_name *return_event_name;
Api_rc *result;

This section describes general use of asynchronous calls with em_wait(). For additional details on em_wait(), refer to the HP FTAM/9000 Reference Manual.

Call functions asynchronously when making multiple requests and when the order in which results are processed does not matter. If you make an asynchronous call, you can perform other operations while your request is being processed. Following are examples of when to call functions asynchronously or synchronously.

  • If you cannot call function B before function A completes, you should call function A synchronously.

  • If copying a file to four different nodes and the processing order does not matter, you would call ft_copy)) asynchronously and then wait on the return_event_names to know when each ft_copy() completed successfully.

The following text describes the sequence of making asynchronous requests and checking for their successful return from the responder.

  1. Submit one or more asynchronous requests, each with a unique return_event_name.

  2. Call em_wait() to determine if the requests returned successfully from the responder; you cannot specify the return_event_name for which you want to wait.

    Though em_wait() function waits on multiple asynchronous calls, it returns return_event_names one at a time and in the order that each call completes.

  3. Check the inout_dcb of the FTAM function (specified by the return_event_name) to determine the result of a completed request. Note, the inout_dcb pointer and structure are not valid until the em_wait() request returns successfully.

    Since events can return in any order, the return_event_name returned may or may not be the first operation you requested or the one on which you are waiting.

    A return_event_name returns only once. Therefore, you should process the inout_dcb for all return_event_names in the order in which they return or track all the return_event_names that return (for future use).

  4. Continue calling em_wait() until you receive the return_event_name you want. If applicable, call em_wait() until all requests are processed.

    NOTE: Do not perform any operations on or with an inout_dcb pointer or structure until em_wait() indicates the call using the inout_dcb is complete.

Following is an example of the use of em_wait(). This example creates and opens a file by asynchronously calling ft_bgroup(), ft_create(), and ft_open(), followed by synchronously calling ft_egroup(). These functions were called with return_event_names of 1, 2, 3, and 0, respectively. The em_wait() function waits on these calls.

struct Ft_bgroup_out_dcb      *bgr_inout_dcb;
struct Ft_create_out_dcb *cre_inout_dcb;
struct Ft_open_out_dcb *ope_inout_dcb;
Em_t time;
Local_event_name return_event_name;
Api_rc result;
int i;
Return_code res;
struct Ft_diagnostic *diag = NULL;
/* This loop waits on the three previously submitted
asynchronous calls. */
for (i = 1; i %<= 3; ++i) {
time = -1;
/* Call em_wait() to receive the latest event. */
res = em_wait(time, & return_event_name, & result);
if (res != SUCCESS)
error_handler(result, diag);
/* Check the result of each function. */
switch (return_event_name) {
case 1:
if (bgr_inout_dcb->result.return_code != SUCCESS)
error_handler(bgr_inout_dcb->result, diag);
break;
case 2:
if (cre_inout_dcb->result.return_code != SUCCESS)
error_handler(cre_inout_dcb->result,
cre_inout_dcb->diagnostic);
break;
case 3:
if (ope_inout_dcb->result.return_code != SUCCESS)
error_handler(ope_inout_dcb->result,
ope_inout_dcb->diagnostic);
break;
default:
break;
}
}

Using em_hp_select()

#include %</opt/ftam/include/map.h>
Return_code
em_hp_select (timeout, return_event_name, nfds, readfds,
writefds, exceptfds, result)
Em_t timeout;
Local_event_name *return_event_name
int *nfds
unsigned *readfds
unsigned *writefds
unsigned *exceptfds
Api_rc *result;

This section describes how to use em_hp_select() and provides two program examples. For additional details, refer to the HP FTAM/9000 Reference Manual.

NOTE: FTAM events are asynchronous FTAM operations that complete. Non-FTAM events consist of any type of descriptor supported by the select(2) system call that becomes readable or writable, or has exceptions pending.

Multiple asynchronous FTAM functions calls are commonly outstanding at the same time. An application may also need to interact with other processes using an interprocess communication mechanism (for instance, HP-UX Domain Sockets or pipes). It may also require response to asynchronous events from a terminal keyboard or window system (for instance, X- Windows).

The MAP 3.0 Event Management interface does not provide an independent method to wait on both FTAM and non-FTAM events simultaneously. Therefore, HP added a proprietary function—em_hp_select()—to provide this capability.

Neither em_wait() nor em_hp_select() automatically return when interrupted by a signal. However, the following section describes a way to make a signal generate a non-FTAM event, causing em_hp_select() to return on receipt of a signal.

Waiting On FTAM and Non-FTAM Events

Use the em_hp_select() function when an application must simultaneously wait for both an FTAM and a non-FTAM event to occur.

Without em_hp_select(), the application would need to implement a "busy- wait" loop to poll for the FTAM and non-FTAM events. However, this technique is very expensive in terms of CPU utilization, and degrades system performance. This is unacceptable for most real-time or highly interactive applications. Therefore, HP provides em_hp_select() as an alternative method for waiting on both FTAM and non-FTAM events.

The em_hp_select() function suspends processing of the application until an event occurs. While the application is suspended (i.e, blocked), it does not contribute to the demand for CPU time. Therefore, the busy-wait logic can be replaced with the following:

em_hp_select(...with indefinite timeout to block until event occurs...)
handle_event))

If you need to wait only on FTAM events, use the em_wait() function. If you need to wait only on non-FTAM events, use the HP-UX select() system call. However, if you need to wait on both types of events simultaneously, use the em_hp_select() function. Any combination of em_wait(), select(), and em_hp_select() within the same program is valid; all three functions are compatible with one another.

The following program example illustrates how to use em_hp_select() to wait on FTAM and non-FTAM events simultaneously. The program reads commands from stdin and starts the requested FTAM operation. The operation is performed asynchronously so that new commands can be read in before the previous operation completes. The operation results are processed as they complete.

This program calls two functions to process the FTAM and non-FTAM events. The logic for these functions is not shown in the example; however, a brief description of each function follows.

read_and_process_command()

This function processes the non-FTAM events by reading and parsing a command line string from stdin. If the command is a "Quit" command, the function returns TRUE to indicate termination. Otherwise, the appropriate FTAM operation is initiated asynchronously. In this case, the function returns FALSE to indicate more commands can be read from stdin.

For example, this function could be a batch entry console for file management. Several file transfers could be started without having to wait for each transfer to complete before starting the next.

map_operation_completed (map_event, map_rc)

This function processes the FTAM events by performing some action on the results of the FTAM operation that completed. The operation is identified by the map_event passed as input. If map_rc equals SUCCESS, the inout_dcb for the operation contains the outcome of the operation. Otherwise, the map_rc equals EME032_IPC_ERROR; the operation fails and the inout_dcb does not contain valid information. The specific actions involved with processing a completed FTAM event are specific to the particular event, and could be as simple as logging the results to an output file.

#include %<stdio.h>
#include %</opt/ftam/include/map.h>
#define BITS_PER_INT 32
#define SET_MASK(f,fds) (fds)[((f)/BITS_PER_INT)] |=
(1%<%<((f)%BITS_PER_INT))
#define TST_MASK(f,fds) ((fds)[((f)/BITS_PER_INT)] &
(1%<%<((f)%BITS_PER_INT)))
main()
{
Bool done;
Local_event_name map_event;
Return_code map_rc;
Api_rc map_result;
char *ret_str;
char *ven_str;
int nfds;
unsigned readfds[2]; /* handles upto 64 fds */
/* Read and process the first command. No FTAM operations are
** outstanding at this time, so do not wait for any to complete.
*/
done = read_and_process_command();
/* Wait indefinitely for MAP and non-MAP (i.e., stdin readable) events
** to occur. If an EME032_IPC_ERROR occurs, the MAP operation
** identified by map_event is treated as having completed with the IPC
** error. Non-MAP events can also return in this case, so they
** are processed as well.
**
** If any other error occurs, there is a programming error when calling
** em_hp_select(); in this case, use em_gperror() and em_fdmemory() to
** translate the error into printable character strings, then
** abort processing so you can fix the coding error.
**
** Continue processing both FTAM and non-FTAM events until a "Quit" command
** is entered as the non-FTAM event.
*/

  while ( ! done )
{
readfds[0] = 0;
readfds[1] = 0;
SET_MASK(stdin, readfds);
nfds = stdin + 1;
map_rc = em_hp_select(FOREVER, & map_event, & nfds, readfds, NULL, NULL,
& map_result);
if ((map_rc == SUCCESS) || (map_rc == EME032_IPC_ERROR))
{
if ((map_event != 0))
map_operation_completed(map_event, map_rc);
if (TST_MASK(stdin, readfds))
done = read_and_process_command();
}
else
{
ret_str = NULL;
ven_str = NULL;
map_rc = em_gperror(& map_result, & ret_str, & ven_str, & map_result);
if (map_rc == SUCCESS)
fprintf(stderr, "%s%s", ret_str, ven_str);
em_fdmemory(ret_str, & map_result);
em_fdmemory(ven_str, & map_result);
exit(1);
}
} /* while */
/* You finished entering commands, but all of the MAP operations may not
** be complete. Since only MAP events are left, em_wait() is used instead
** of em_hp_select(). An EME002_EXP_EMPTY result indicates all MAP
** operations have completed.
*/
done = FALSE;
do {
map_rc = em_wait(FOREVER, & map_event, & map_result);
if ((map_rc == SUCCESS) || (map_rc == EME032_IPC_ERROR))
map_operation_completed(map_event, map_rc);
else if (map_rc == EME002_EXP_EMPTY)
done = TRUE;
else
{
done = TRUE;
ret_str = NULL;
ven_str = NULL;
map_rc = em_gperror(& map_result, & ret_str, & ven_str, & map_result);
if (map_rc == SUCCESS)
fprintf(stderr, "%s%s", ret_str, ven_str);
em_fdmemory(ret_str, & map_result);
em_fdmemory(ven_str, & map_result);
exit(2);
}
} while ( ! done );
exit(0);
} /* main */

Handling Signal Interrupts

Suppose an application needs the em_wait() function to return prematurely if a signal interrupt occurs. One case where this is applicable is when receipt of a signal should cause a new FTAM operation to be initiated or an outstanding operation to be aborted (e.g., the application is being terminated abruptly). Since FTAM functions are not reentrant, the application needs to force em_wait() to return prematurely so the appropriate action can be taken upon receipt of the signal.

The em_wait() and em_hp_select() functions cannot detect signal interrupts and automatically return. However, you can cause em_hp_select() to return when interrupted by a signal. This involves translating the signal interrupt into an em_hp_select() non-FTAM event while executing the signal handler. When em_hp_select() resumes processing after the signal handler completes, the non-FTAM event will be detected and em_hp_select() will return.

Several techniques exist to translate the signal interrupt into an em_hp_select() non-FTAM event. One way is to use an HP-UX pipe as follows:

  1. Open the pipe for both reading and writing within the application program.

  2. For the expected signals, install a signal handler that writes the trapped signal value to the pipe. This will cause the pipe to become readable.

  3. Replace calls to em_wait() (which waits for only FTAM events) with calls to em_hp_select(). Initialize the readfds mask to include the read descriptor for the pipe. If a signal interrupt occurs while executing or blocking within em_hp_select(), the pipe will become readable and cause em_hp_select() to return.

  4. After em_hp_select() returns, read the signal value from the pipe so that the notification will be cleared; then take the appropriate action based on the signal value.

The following program example illustrates how to use em_hp_select() and an HP-UX pipe to implement the signal handling technique described previously.

#include %<signal.h>
#include %</opt/ftam/include/map.h>
#define BITS_PER_INT 32
#define SET_MASK(f,fds) (fds)[((f)/BITS_PER_INT)] |= (1%<%<((f)%BITS_PER_INT))
#define TST_MASK(f,fds) ((fds)[((f)/BITS_PER_INT)] & (1%<%<((f)%BITS_PER_INT)))
#define READ 0
#define WRITE 1
int sig_pipe[2]; /* Pipe r/w descriptors used to queue signals */
void
signal_handler(sigval)
int sigval;
{
/* Put signal on the pipe to make the pipe readable. This will cause
** em_hp_select() to return.
*/
write(sig_pipe[WRITE], & sigval, sizeof(int));
/* Perform other signal handling logic if any. */
}
main()
{
int sigval; /* The signal value read from pipe */
struct sigvec vec; /* sigvector for installing handler */
Local_event_name map_event; /* MAP Event Name */
Return_code map_rc; /* MAP return code */
Api_rc map_result; /* MAP result structure */
int nfds; /* File descriptor bound */
unsigned readfds[2]; /* File descriptor mask */
/*
** Create the HP-UX pipe which is used to translate the signal interrupt
** into an em_hp_select() non-MAP event.
*/
pipe (sig_pipe);

   /* Install the signal handler for the signal you want to trap.  */
vec.sv_handler = signal_handler;
vec.sv_mask = 0;
vec.sv_flags = 0;
sigvector(signal_you_want_to_trap, & vec, NULL);
/* Initiate the asynchronous FTAM operations. The code for
** initiating these operations is not shown in this example.
*/
/* Wait for a MAP operation to complete or a signal to be caught.
** This is done by blocking on both MAP events and the sig_pipe
** to become readable.
*/
readfds[0] = 0;
readfds[1] = 0;
SET_MASK(sig_pipe[READ], readfds);
nfds = sig_pipe[READ] + 1;
map_rc = em_hp_select(FOREVER, & map_event, & nfds, readfds, NULL, NULL,
& map_result);
if ((map_rc == SUCCESS) || (map_rc == EME032_IPC_ERROR))
{
if (map_event != 0)
{
/* Process the results of the completed MAP operation. The
** code for this function is not shown in this example.
*/
map_operation_completed(map_event, map_rc);
}
if (TST_MASK(sig_pipe[READ], readfds))
{
/* em_hp_select() was interrupted by a signal. Remove the signal
** value from the pipe to clear the interrupt notification.
*/
read(sig_pipe[READ], & sigval, sizeof(int));
/* Perform the application specific logic to be done when
** em_hp_select() unblocks because of a signal.
*/
}
}
else
{
/* Handle the em_hp_select() error. See Example 1. */
}

Using em_hp_sigio()

#include %</opt/ftam/include/map.h>
Return_code
em_hp_sigio (action, pid, result)
Unit32 action;
Sint32 pid;
Api_rc *result;

This section describes how to use em_hp_select() and provides a program example. For additional details, refer to the HP FTAM/9000 Reference Manual.

Use em_hp_sigio() to enable the MAP Event Management interface to generate SIGIO signals whenever an asynchronous MAP event is pending. Unlike the other MAP event management functions, em_hp_sigio() does not return a MAP event to the caller. Instead, it merely puts the MAP event management interface into an extended capability mode.

By using this capability, you can suspend the processing of your application until any of a variety of signals or semaphore operations cause your application to resume execution. Then, only after the SIGIO signal has been received do you need to call em_wait() to obtain the MAP event that is pending. Furthermore, since you know the MAP event is already pending, you can call em_wait() with a zero timeout to obtain the event and return immediately.

The following program example illustrates one possible use of em_hp_sigio(). The program initiates and processes two types of events: MAP events in the form of FTAM and/or FTAM asynchronous operations, and Non-MAP events that take the form of SIGUSR1 signals. The em_hp_sigio() function is used to enable SIGIO signal notification in the MAP Event Management interface, and em_wait() is used to process the MAP event after SIGIO is caught.

/*
** Sample program for em_hp_sigio()
**
** This program is designed with three primary components:
**
** * a central control/dispatch component
** * a MAP event processing component
** * a Non-MAP event processing component
**
** The central control/dispatch component makes use of an array of semaphores
** to manage program suspension and resumption, and to keep track of which
** components (MAP or Non-MAP) have work to do. Additionally, a signal
** handler is installed for the MAP and Non-MAP generated signals which
** manipulates the semaphore array. The SIGIO signal is used to notify the
** control/dispatch component that a MAP event needs to be processed, and the
** SIGUSR1 signal is used for Non-MAP events.
**
** The MAP and Non-MAP processing components are referenced as external
** functions. Details of these components are specific to each application
** and are, therefore, not included here. Note, calling em_wait() to obtain
** the MAP event would normally be included in the MAP specific processing
** component, but em_wait() is pulled out into the main component here to
** demonstrate the relationship between em_hp_sigio() and em_wait().
*/
#include %<stdio.h>
#include %<errno.h>
#include %<signal.h>
#include %<sys/types.h>
#include %<sys/ipc.h>
#include %<sys/sem.h>
#include %</opt/ftam/include/map.h>
/*
** Functions and variables not provided by the demonstration program.
*/
extern Bool operations_to_wait_on_and_process;
extern void initiate_MAP_operation();
extern void process_MAP_operation();
extern void initiate_NON_MAP_operation();
extern void process_NON_MAP_operation();
/*
** Semaphores used to manage suspend/resume activity
**
** Three semaphores are used to manage the MAP and Non-MAP asynchronous
** activity. One semaphore is used to control the suspension and resumption
** of process. Another semaphore is used to keep track of the number of
** pending events for each event type, MAP and Non-MAP in this case.
**
** The semaphores are operated on by a set of functions included following
** the main program. The functions provide logical P and V operations on a
** set of semaphores, based on HP-UX semaphore operations (system calls).
*/
#define NUM_SEMAPHORES 3
#define SEM_CONTROL 1 /* Used for suspend & resume control */
#define SEM_MAP 2 /* Used to track pending MAP events */
#define SEM_NON_MAP 4 /* Used to track pending Non-MAP events */

#define WAIT            0       /* Tells sem_p)) to block if necessary     */
#define NO_WAIT 1 /* Tells sem_p() to return immediately */
int sem_id; /* The semaphore array for async mgmt */
int sem_create(); /* Create semaphores on the system */
void sem_remove(); /* Remove semaphores from the system */
int sem_p(); /* Perform a P (get) operation */
void sem_v(); /* Perform a V (give) operation */
/*
** Signals and signal handler used to manage asynchronous event notification.
** The signal_handler logic is included following the main program.
*/
#define SIG_MAP SIGIO /* MAP notification signal */
#define SIG_NON_MAP SIGUSR1 /* Non-MAP signal (for example) */
void signal_handler(); /* Signal handler for async event mgmt */
/*
** MAIN PROGRAM
*/
main()
{
Local_event_name map_event_name; /* MAP 3.0 event name (identifier) */
Return_code map_rc; /* MAP 3.0 function return code */
Api_rc map_result; /* MAP 3.0 result structure */
struct sigvec vec; /* Signal Vector for event handler */
printf("Demonstration program for em_hp_sigio()\n");
/*
** Create and initialize the semaphore array for process suspension and
** resumption.
*/
printf("Creating semaphore for process suspend & resume.\n");
sem_id = sem_create(NUM_SEMAPHORES);
/*
** Install the signal handler to catch interrupts for each signal used
** as an event notification.
*/
printf("Installing signal handlers for MAP and Non-MAP events\n");
vec.sv_handler = signal_handler;
vec.sv_mask = 0;
vec.sv_flags = 0;
sigvector(SIGIO, & vec, NULL); /* MAP events */
sigvector(SIGUSR1, & vec, NULL); /* Non-MAP events */
/*
** Put the MAP 3.0 Interface into SIGIO notification mode. This causes
** MAP Event Management to generate a SIGIO signal whenever there is
** an asynchronous event to process.
**
** Note, the process to signal is the local (this) process. The process
** id is negated to distinguish it from a process group id.
*/
printf("Calling em_hp_sigio() to enable SIGIO notification for MAP.\n");
map_rc = em_hp_sigio(EM_SIGIO_ENABLE, getpid(), & map_result);
if (map_rc != SUCCESS)
{
fprintf(stderr, "ERROR: em_hp_sigio(ENABLE) failed, %d\n", map_rc);
exit(1);
}

    /*
** Activate MAP 3.0 Application Entity for FTAM or FTAM, then initiate
** asynchronous MAP 3.0 operations.
*/
initiate_MAP_operation();
/*
** Initialize and initiate Non-MAP asynchronous operations.
*/
initiate_NON_MAP_operation();
while (operations_to_wait_on_and_process)
{
/*
** Suspend processing until an asynchronous event occurs.
*/
printf("\nSuspending processing until an event occurs.\n");
sem_p(sem_id, SEM_CONTROL, WAIT);
/*
** Processing has resumed. Determine the event type that occurred.
*/
printf("Resuming processing after semaphore popped.\n");
/*
** Process MAP 3.0 (FTAM or FTAM) event if one is pending.
**
** A non-blocking sem_p() operation is used to atomically test and
** decrement the pending MAP event count. If a MAP event is pending,
** sem_p() returns zero; otherwise, it returns non-zero.
**
** Note, calling em_hp_sigio() earlier merely put the MAP interface
** into SIGIO notification mode. You must still call em_wait() to
** obtain the event name for the MAP 3.0 operation that triggered
** the signal notification. Furthermore, the operation may only be
** partially complete. Calling em_wait() processes the MAP event as
** much as possible, but returns EME005_TIMEOUT if the event is not
** completely processed.
*/
if (sem_p(sem_id, SEM_MAP, NO_WAIT) == 0)
{
printf("Calling em_wait() to obtain MAP event.\n");
map_rc = em_wait(0, & map_event_name, & map_result);
if (map_rc == SUCCESS)
process_MAP_operation(map_event_name);
else if (map_rc == EME005_TIMEOUT)
printf("em_wait timeout: operation partially complete\n");
else
fprintf(stderr, "ERROR: em_wait() failed, %d\n", map_rc);
}

        /*
** Process Non-MAP event if one is pending.
**
** A non-blocking sem_p() operation is used to atomically test and
** decrement the pending Non-MAP event count. If a Non-MAP event is
** pending, sem_p() returns zero; otherwise, it returns non-zero.
**
** Note, event processing is specific to your own application;
** details are not included in this example.
*/
if (sem_p(sem_id, SEM_NON_MAP, NO_WAIT) == 0)
{
process_NON_MAP_operation();
}
} /* while - operations to process */
/*
** Disable SIGIO notification for the MAP 3.0 Interface.
** Note, the process id parameter is ignored so any value is fine.
*/
printf("\nCalling em_hp_sigio() to disable SIGIO notification.\n");
map_rc = em_hp_sigio(EM_SIGIO_DISABLE, 0, & map_result);
if (map_rc != SUCCESS)
fprintf(stderr, "ERROR: em_hp_sigio(DISABLE) failed, %d\n", map_rc);
    /*
** Remove semaphore resources.
*/
printf("Cleaning up semaphore resources.\n");
sem_remove(sem_id);
exit(0);
} /* end main() */
/*
** Signal Handler for Event Notification
**
** The event notification signal handler performs a semaphore V operation
** on the suspend/resume semaphore, plus the specific event type semaphore.
*/
void
signal_handler(sig)
int sig;
{
unsigned long sem_mask;
printf("Signal handler taken for signal %d\n", sig);
/*
** Always included the Control semaphore in the semaphore mask. This is
** what causes the main program to resume execution.
*/
sem_mask = SEM_CONTROL;

    /*
** Determine the event type based on the signal received.
** Update the semaphore mask to include the event type specific
** semaphore.
*/
if (sig == SIG_MAP)
sem_mask |= SEM_MAP;
else if (sig == SIG_NON_MAP)
sem_mask |= SEM_NON_MAP;
else {
fprintf(stderr, "ERROR: unsupported signal, %d\n", sig);
exit(1);
}
/*
** Perform a V (give) operation on the specified semaphores so that the
** process can resume (if suspended), and the event count for the given
** type is incremented atomically.
*/
sem_v(sem_id, sem_mask);
} /* signal_handler */
/*
** sem_create()
**
** This function creates a semaphore array for the specified number of
** semaphores (up to 32) and initializes them to an "unblocked" state.
*/
int
sem_create(sem_cnt)
int sem_cnt;
{
int sem_id;
ushort sem_val[sizeof(unsigned long)];
sem_id = semget(IPC_PRIVATE, sem_cnt, IPC_CREAT | 0600);
if (sem_id == -1)
{
fprintf(stderr, "ERROR: creating semaphore, errno %d\n", errno);
exit(1);
}
memset(sem_val, 0, sizeof(sem_val));
if (semctl(sem_id, 0, SETALL, sem_val) == -1)
{
fprintf(stderr, "ERROR: initializing semaphore, errno %d\n", errno);
exit(1);
}
return(sem_id);
}

/*
** sem_remove()
**
** This function removes the semaphore array from the system.
*/
void
sem_remove(sem_id)
int sem_id;
{
if (semctl(sem_id, 0, IPC_RMID, 0) == -1)
{
fprintf(stderr, "ERROR: removing semaphore, errno %d\n", errno);
exit(1);
}
}
/*
** sem_p()
**
** This function performs a semaphore P (get) operation on the set of
** semaphores specified by 'sem_mask'. The sem_mask is defined such that
** semaphore number N is represented by bit (1 %< (N-1)) in the mask.
**
** If the 'sem_nowait' flag is FALSE, processing is suspended until blocking
** conditions for all of the specified semaphores have cleared.
** If the 'sem_nowait' flag is TRUE, processing continues immediately and the
** return value indicates whether a blocking condition exists or not.
**
** If all blocking conditions are cleared, the function returns zero.
** Otherwise, non-zero returns.
*/
int
sem_p(sem_id, sem_mask, sem_nowait)
int sem_id;
unsigned long sem_mask;
int sem_nowait;
{
struct sembuf sem_ops[sizeof(unsigned long)];
int sem_num = 0;
int sem_cnt = 0;
int rc = 0;
while ((sem_num %< sizeof(unsigned long)) & & sem_mask)
{
if (sem_mask & 1)
{
sem_ops[sem_cnt].sem_num = sem_num;
sem_ops[sem_cnt].sem_op = -1;
sem_ops[sem_cnt].sem_flg = (sem_nowait ? IPC_NOWAIT : 0);
sem_cnt++;
}
sem_num++;
sem_mask >= 1;
}

    if (sem_cnt > 0)
{
do {
rc = semop(sem_id, sem_ops, sem_cnt);
} while ((rc == -1) & & (errno == EINTR));
if ((rc == -1) & & !((sem_nowait) & & (errno == EAGAIN)))
{
fprintf(stderr, "ERROR: semaphore P (get), errno %d\n", errno);
exit(1);
}
}
return(rc);
} /* sem_p */
/*
** sem_v()
**
** This function performs a semaphore V (give) operation on the set of
** semaphores specified by 'sem_mask'. The sem_mask is defined such that
** semaphore number N is represented by bit (1 %< (N-1)) in the mask.
*/
void
sem_v(sem_id, sem_mask)
int sem_id;
unsigned long sem_mask;
{
struct sembuf sem_ops[sizeof(unsigned long)];
int sem_num = 0;
int sem_cnt = 0;
int rc;
while ((sem_num %< sizeof(unsigned long)) & & sem_mask)
{
if (sem_mask & 1)
{
sem_ops[sem_cnt].sem_num = sem_num;
sem_ops[sem_cnt].sem_op = 1;
sem_ops[sem_cnt].sem_flg = 0;
sem_cnt++;
}
sem_num++;
sem_mask >= 1;
}
    if (sem_cnt > 0)
{
do {
rc = semop(sem_id, sem_ops, sem_cnt);
} while ((rc == -1) & & (errno == EINTR));
        if (rc == -1)
{
fprintf(stderr, "ERROR: semaphore V (give), errno %d\n", errno);
exit(1);
}
}
} /* sem_v */

Printable version
Privacy statement Using this site means you accept its terms Feedback to webmaster
© 1997 Hewlett-Packard Development Company, L.P.