Signals and Signal Handling


The UNIX operating system supports a wide range of signals. UNIX signals are software interrupts that catch or indicate different types of events. Windows , on the other hand, supports only a small set of signals that is restricted to exception events only. Consequently, converting UNIX code to Win32 requires the use of new techniques replacing the use of some UNIX signals.

The Windows signal implementation is limited to the following signals (Table 9.3).

Table 9.3: Windows Signals

Signal

Meaning

SIGABRT

Abnormal termination

SIGFPE

Floating-point error

SIGILL

Illegal instruction

SIGINT

CTRL+C signal

SIGSEGV

Illegal storage access

SIGTERM

Termination request

Note  

When a CTRL+C interrupt occurs, Win32 operating systems generate a new thread to handle the interrupt. This can cause a single-thread application, such as one ported from UNIX, to become multithreaded, which may in unexpected behavior.

When an application uses other signals not supported in Windows, you have two choices:

  • Use additional libraries that provide required signals, such as those providedby Microsoft Services for UNIX at: http://www.microsoft.com/Windows2000/sfu .

  • Use a comparable Windows mechanism, such as Windows Messages.

This section focuses on the Windows mechanisms that you can use to replace theuse of some UNIX signals. Table 9.4 shows the recommended mechanisms that you can use to replace common UNIX signals. There are three main mechanisms:

  • Native signals

  • Event objects

  • Messages

    Table 9.4: UNIX Signals and Replacement Mechanisms

    Signal Name

    Description

    Link to reference material

    SIGABRT

    Abnormal termination

    SIGABRT

    SIGALRM

    Time-out alarm

    SetTimer “ WM_TIMER - CreateWaitableTimer

    SIGCHLD

    Change in status of child

    WaitForSingleObject

    SIGCONT

    Continue stopped process

    WaitForSingleObject

    SIGFPE

    Floating point exception

    SIGFPE

    SIGHUP

    Hangup

    NA

    SIGILL

    Illegal hardware instruction

    SIGILL

    SIGINT

    Terminal interrupt character

    WM_CHAR

    SIGKILL

    Termination

    WM_QUIT

    SIGPIPE

    Write to pipe with no readers

    WaitForSingleObject

    SIGQUIT

    Terminal Quit character

    WM_CHAR

    SIGSEGV

    Invalid memory reference

    SIGSEGV

    SIGSTOP

    Stop process

    WaitForSingleObject

    SIGTERM

    Termination

    SIGTERM

    SIGTSTP

    Terminal Stop character

    WM_CHAR

    SIGTTIN

    Background read from control tty

    NA

    SIGTTOU

    Background write to control tty

    NA

    SIGUSR1

    User defined signal

    SendMessage “ WM_APP

    SIGUSR2

    User defined signal

    SendMessage “ WM_APP

    Note  

    Only POSIX signals are considered in this table (that is, Seventh Edition, System V,and BSD signals are not).

This section discusses how you can use the three mechanisms listed in Table 9.4to convert the parts of your code that use signals into the Windows environment.

Another mechanism that can be useful when converting some UNIX uses of signals to Windows is event kernel objects. For more information on these objects, see the CreateEvent example in Logging System Messages later in this chapter.

Using Native Signals in Windows

In the following example, the simple case of catching SIGINT to detect CTRL-C is demonstrated. As you can see from the two source listings, support for handling native signals in UNIX and Win32 is very similar.

Managing Signals in UNIX

 #include <unistd.h> #include <stdio.h> #include <signal.h> /*  The intrpt function reacts to the signal passed in the parameter signum.     This function is called when a signal occurs.     A message is output, then the signal handling for SIGINT is reset     (by default generated by pressing CTRL-C) back to the default behavior. */ void intrpt(int signum) {     printf("I got signal %d\n", signum);     (void) signal(SIGINT, SIG_DFL); } /*  main intercepts the SIGINT signal generated when Ctrl-C is input.     Otherwise, sits in an infinite loop, printing a message once a second. */ int main() {     (void) signal(SIGINT, intrpt);     while(1) {         printf("Hello World!\n");         sleep(1);     } } 

Managing Signals in Windows

 #include <windows.h> #include <signal.h> #include <stdio.h> void intrpt(int signum) {     printf("I got signal %d\n", signum);     (void) signal(SIGINT, SIG_DFL); } /*  main intercepts the SIGINT signal generated when Ctrl-C is input.     Otherwise, sits in an infinite loop, printing a message once a second. */ void main() {     (void) signal(SIGINT, intrpt);     while(1) {         printf("Hello World!\n");         Sleep(1000);     } } 
Note  

By default, signal terminates the calling program with exit code 3, regardless of the value of sig. For more information, see http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vclib/html/_crt_signal.asp .

With the exception of requiring an additional header file, and the different signature of the sleep function, these two examples are identical. Unfortunately, this is the extent of the similarities in signal handling between the two platforms.

Replacing UNIX Signals Within Windows

UNIX uses signals to send alerts to processes when specific actions occur. A UNIX application would use the kill function to activate signals internally. As discussed earlier, Win32 provides only limited support for signals. As a result, you have to rewrite your code to use another form of event notification in Win32.

The following example illustrates how you would convert UNIX code to Windows messages or event objects. It shows a simple main that forks a child process, which issues the SIGALRM signal. The parent process catches the alarm and outputs a message when it is received.

Using the SIGALRM Signal in UNIX

 #include <unistd.h> #include <stdio.h> #include <signal.h> static int alarm_fired = 0; /*  The alrm_bell function simulates an alarm clock.  */ void alrm_bell(int sig) {     alarm_fired = 1; } int main() {     int pid; /*  Child process waits for 5 secs before sending SIGALRM to its parent. */     printf("alarm application starting\n");     if((pid = fork()) == 0) {         sleep(5);         kill(getppid(), SIGALRM);         exit(0);     } /*  Parent process arranges to catch SIGALRM with a call to signal     and then waits for the child process to send SIGALRM. */     printf("waiting for alarm\n");     (void) signal(SIGALRM, alrm_bell);     pause();     if (alarm_fired)         printf("Ring...Ring!\n");     printf("alarm application done\n");     exit(0); } 

Replacing UNIX Signals with Windows Messages

In the first Win32 example that follows , a form of Microsoft Windows Messages is used to signal the parent process. In the example, the SetTimer function is used to signal the parent process that an alarm has been activated. Although code could have been created to do the timing, using the SetTimer function greatly simplifies this example.

Another advantage of using SetTimer is that the callback function is invoked in the same thread that calls SetTimer . No synchronization is necessary.

If the requirements are simple, consider using a thread to act as a timer thread, which simply calls Sleep to create the desired delay. At the end of the delay, a callis made to a timer callback function. The problem with this approach is that the callback function is called from a different thread than your primary thread. If the callback function requires resources that are thread specific, you will need to use one of the appropriate synchronization mechanisms discussed in Threads later in this chapter.

Additional code has been added to the example so that an application using this code can catch any standard Windows message as well as application- and user-defined messages. You can use these messages to engineer solutions to other signals that are not directly supported by the native signal implementation in Win32.

Replacing SIGALRM Using Windows Messages

 #include <windows.h> #include <stdio.h> #include <conio.h> #include <stdlib.h> static int alarm_fired = 0; /*  The alrm_bell function simulates an alarm clock. */ VOID CALLBACK alrm_bell(HWND hwnd, UINT uMsg, UINT idEvent, DWORD dwTime) {     alarm_fired = 1;     printf("Ring...Ring!\n"); } void main() {     printf("alarm application starting\n"); /* Set up a 5 second timer which calls alrm_bell */     SetTimer(0, 0, 5000, (TIMERPROC)alrm_bell);     printf("waiting for alarm\n");     MSG msg = { 0, 0, 0, 0 };   /*  Get the message, & dispatch.  This causes alrm_bell to be invoked. */     while(!alarm_fired)         if (GetMessage(&msg, 0, 0, 0)) {             if (msg.message == WM_TIMER)                 printf("WM_TIMER\n");             DispatchMessage(&msg);         }     printf("alarm application done\n");     exit(0); } 

Notice in this example that the WM_TIMER message is issued and captured by the GetMessage function. If you remove the call to DispatchMessage , the alrm_bell function would never be called, but the WM_TIMER message would be received. With this simple application, you can capture a variety of Windows messages. Moreover, if you want to trigger the callback function before the specified time, you can use the PostMessage (WM_TIMER) call. This is analogous to using the kill function to send a signal in UNIX.

Replacing UNIX Signals with Windows Event Objects

Some events that UNIX handles through signals are represented in Win32 as objects. Functions are available to integrate these event objects. An example of these functions is WaitForSingleObject .

In the example code that follows, a timer object is used to signal when a timed interval has elapsed. Again, this example provides the same functionality as the preceding UNIX SIGALRM example.

Note  

While this illustration encompasses the process in a single thread, this is not a requirement. The timer object can be tested and waited for in other threads if necessary.

Replacing SIGALRM Using Event Objects

 #define _WIN32_WINNT 0X0500 #include <windows.h> #include <stdio.h> #include <conio.h> #include <stdlib.h> void main() {     HANDLE hTimer = NULL;     LARGE_INTEGER liDueTime;     liDueTime.QuadPart = -50000000;     printf("alarm application starting\n"); // Set up a 5 second timer object     hTimer = CreateWaitableTimer(NULL, TRUE, "WaitableTimer");     SetWaitableTimer(hTimer, &liDueTime, 0, NULL, NULL, 0); // Now wait for the alarm     printf("waiting for alarm\n");   // Wait for the timer object     WaitForSingleObject(hTimer, INFINITE);     printf("Ring...Ring!\n");     printf("alarm application done\n");     exit(0); } 

Porting the Sigaction Call

Win32 does not support sigaction . The UNIX example that follows shows how sigaction is typically used in a UNIX application. In this example, the handler for the SIGALRM signal has been set. How this code can be converted to use Windows Messages was shown earlier. You could also use Windows Messages here if you prefer.

Note  

To terminate this application from the keyboard, press CTRL+\.

 #include <unistd.h> #include <stdio.h> #include <signal.h> void intrpt(int signum) {     printf("I got signal %d\n", signum); } int main() {     struct sigaction act;     act.sa_handler = intrpt;     sigemptyset(&act.sa_mask);     act.sa_flags = 0;     sigaction(SIGINT, &act, 0);   while(1) {     printf("Hello World!\n");     sleep(1);   } } 



UNIX Application Migration Guide
Unix Application Migration Guide (Patterns & Practices)
ISBN: 0735618380
EAN: 2147483647
Year: 2003
Pages: 134

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net