Sun Microsystems, Inc.
spacer |
black dot
9.  Real-time Programming and Administration High Performance I/O Synchronized I/O Synchronization Modes  Previous   Contents   Next 

Synchronizing a File

fsync(3C) and fdatasync(3RT) explicitly synchronize a file to secondary storage.

The fsync(3C) routine guarantees that the interface is synchronized at the I/O file integrity completion level, while fdatasync(3RT) guarantees that the interface is synchronized at the I/O data integrity completion level.

Applications can synchronize each I/O operation before the operation completes. Setting the O_DSYNC flag on the file description by using open(2) or fcntl(2) ensures that all I/O writes (write(2) and aiowrite(3AIO)) have reached I/O data completion before the operation is indicated as completed. Setting the O_SYNC flag on the file description ensures that all I/O writes have reached completion before the operation is indicated as completed. Setting the O_RSYNC flag on the file description ensures that all I/O reads read(2) and aio_read(3RT) have reached the same level of completion as request for writes by the setting, O_DSYNC or O_SYNC, on the descriptor.

Interprocess Communication

This section describes the interprocess communication (IPC) interfaces of SunOS as they relate to real-time processing. Signals, pipes, FIFOs (named pipes), message queues, shared memory, file mapping, and semaphores are described here. For more information about the libraries, interfaces, and routines useful for interprocess communication, see Chapter 5, Interprocess Communication .

Processing Signals

The sender can use sigqueue(3RT) to send a signal together with a small amount of information to a target process.

To queue subsequent occurrences of a pending signal, the target process must have the SA_SIGINFO bit set for the specified signal. See the sigaction(2) man page.

The target process normally receive signals asynchronously. To receive signals synchronously, block the signal and call either sigwaitinfo(3RT) or sigtimedwait(3RT). See the sigprocmask(2) man page. This causes the signal to be received synchronously, with the value sent by the caller of sigqueue(3RT) stored in the si_value member of the siginfo_t argument. Leaving the signal unblocked causes the signal to be delivered to the signal handler specified by sigaction(2), with the value appearing in the si_value of the siginfo_t argument to the handler.

A specified number of signals with associated values can be sent by a process and remain undelivered. Storage for {SIGQUEUE_MAX} signals is allocated at the first call to sigqueue(3RT). Thereafter, a call to sigqueue(3RT) either successfully enqueues at the target process or fails within a bounded amount of time.

Pipes, Named Pipes, and Message Queues

Pipes, named pipes, and message queues all behave similarly to character I/O devices. They have different methods of connecting. See "Pipes Between Processes" for more information about pipes. See "Named Pipes" for more information about named pipes. See "System V Messages" and "POSIX Messages" for more information about message queues.


Semaphores are also provided in both System V and POSIX styles. See "System V Semaphores" and "POSIX Semaphores" for more information.

Note that using semaphores can cause priority inversions unless these are explicitly avoided by the techniques mentioned earlier in this chapter.

Shared Memory

The fastest way for processes to communicate is directly, through a shared segment of memory. The major difficulty with shared memory is that results can be wrong when more than two processes are trying to read and write in the shared memory at the same time.

Asynchronous Networking

This section introduces asynchronous network communication, using sockets or Transport-Level Interface (TLI) for real-time applications. Asynchronous networking with sockets is done by setting an open socket, of type SOCK_STREAM, to asynchronous and non blocking (see "Asynchronous Socket I/O in "Advanced Topics" in Network Interface Guide). Asynchronous network processing of TLI events is supported using a combination of STREAMS asynchronous features and the non-blocking mode of the TLI library routines (see "Asynchronous Networking" in Network Interface Guide).

For more information on the Transport-Level Interface, see "Socket Interfaces" in Network Interface Guide.

Modes of Networking

Both sockets and transport-level interface provide two modes of service: connection-mode and connectionless-mode.

Connection-mode service is circuit-oriented and enables the transmission of data over an established connection in a reliable, sequenced manner. It also provides an identification procedure that avoids the overhead of address resolution and transmission during the data transfer phase. This service is attractive for applications that require relatively long-lived, datastream-oriented interactions.

Connectionless-mode service is message-oriented and supports data transfer in self-contained units with no logical relationship required among multiple units. All information required to deliver a unit of data, including the destination address, is passed by the sender to the transport provider, together with the data, in a single service request. Connectionless-mode service is attractive for applications that involve short-term request/response interactions and do not require guaranteed, in-sequence delivery of data. Connectionless transports are generally unreliable.

Timing Facilities

This section describes the timing facilities available for real-time applications under SunOS. Real-time applications that use these mechanisms require detailed information from the man pages of the routines listed in this section.

The timing interfaces of SunOS fall into two separate areas of functionality: timestamps and interval timers. The timestamp interfaces provide a measure of elapsed time and enable the application to measure the duration of a state or the time between events. Interval timers allow an application to wake up at specified times and to schedule activities based on the passage of time. Although an application can poll a timestamp interface to schedule itself, such an application would monopolize the processor to the detriment of other system interfaces.

Timestamp Interfaces

Two interfaces provide timestamps. gettimeofday(3C) provides the current time in a timeval structure, representing the time in seconds and microseconds since midnight, Greenwich Mean Time, on January 1, 1970. clock_gettime, with a clockid of CLOCK_REALTIME, provides the current time in a timespec structure, representing in seconds and nanoseconds the same time interval returned by gettimeofday(3C).

SunOS uses a hardware periodic timer. For some workstations, this is the sole timing information, and the accuracy of timestamps is limited to the resolution of that periodic timer. For other platforms, a timer register with a resolution of one microsecond means that timestamps are accurate to one microsecond.

Interval Timer Interfaces

Real-time applications often schedule actions using interval timers. Interval timers can be either of two types: a one-shot type or a periodic type.

A one-shot is an armed timer that is set to an expiration time relative to either a current time or an absolute time. The timer expires once and is disarmed. This type of a timer is useful for clearing buffers after the data has been transferred to storage, or to time-out an operation.

A periodic timer is armed with an initial expiration time, either absolute or relative, and a repetition interval. Each time the interval timer expires, it is reloaded with the repetition interval and rearmed. This timer is useful for data logging or for servo-control. In calls to interval timer interfaces, time values smaller than the resolution of the system hardware periodic timer are rounded up to the next multiple of the hardware timer interval, which is typically 10ms.

There are two sets of timer interfaces in SunOS. The setitimer(2) and getitimer(2) interfaces operate fixed set timers, called the BSD timers, using the timeval structure to specify time intervals. The POSIX timers, created with timer_create(3RT), operate the POSIX clock, CLOCK_REALTIME. POSIX timer operations are expressed in terms of the timespec structure.

The getitimer(2) and setitimer(2) functions retrieve and establish, respectively, the value of the specified BSD interval timer. The three BSD interval timers available to a process include a real-time timer designated ITIMER_REAL. If a BSD timer is armed and allowed to expire, the system sends a signal appropriate to the timer to the process that set the timer.

The timer_create(3RT) routine can create up to TIMER_MAX POSIX timers. The caller can specify what signal and what associated value are sent to the process when the timer expires. The timer_settime(3RT) and timer_gettime(3RT) routines retrieve and establish respectively the value of the specified POSIX interval timer. POSIX timers can expire while the required signal is pending delivery. The timer expirations are counted, and timer_getoverrun(3RT) retrieves the count. timer_delete(3RT) deallocates a POSIX timer.

The following example illustrates how to use setitimer(2) to generate a periodic interrupt, and how to control the arrival of timer interrupts.

Example 9-2 Controlling Timer Interrupts

#include	<unistd.h>
#include	<signal.h>
#include	<sys/time.h>

#define TIMERCNT 8

void timerhandler();
int	 timercnt;
struct	 timeval alarmtimes[TIMERCNT];

	struct itimerval times;
	sigset_t	sigset;
	int		i, ret;
	struct sigaction act;
	siginfo_t	si;

	/* block SIGALRM */
	sigemptyset (&sigset);
	sigaddset (&sigset, SIGALRM);
	sigprocmask (SIG_BLOCK, &sigset, NULL);

	/* set up handler for SIGALRM */
	act.sa_action = timerhandler;
	sigemptyset (&act.sa_mask);
	act.sa_flags = SA_SIGINFO;
	sigaction (SIGALRM, &act, NULL);
	 * set up interval timer, starting in three seconds,
	 *	then every 1/3 second
	times.it_value.tv_sec = 3;
	times.it_value.tv_usec = 0;
	times.it_interval.tv_sec = 0;
	times.it_interval.tv_usec = 333333;
	ret = setitimer (ITIMER_REAL, &times, NULL);
	printf ("main:setitimer ret = %d\n", ret);

	/* now wait for the alarms */
	sigemptyset (&sigset);
	timerhandler (0, si, NULL);
	while (timercnt < TIMERCNT) {
		ret = sigsuspend (&sigset);

void timerhandler (sig, siginfo, context)
	int		sig;
	siginfo_t	*siginfo;
	void		*context;
	printf ("timerhandler:start\n");
	gettimeofday (&alarmtimes[timercnt], NULL);
	printf ("timerhandler:timercnt = %d\n", timercnt);

printtimes ()
	int	i;

	for (i = 0; i < TIMERCNT; i++) {
		printf("%ld.%0l6d\n", alarmtimes[i].tv_sec,

  Previous   Contents   Next