[fpc-devel]Problems with Linux signal calls.

Lloyd B. Park lpark at kent.edu
Tue Jan 6 15:26:15 CET 2004


I found a bug in Linux signal handling which effects both the 1.0.10 and 
1.9.0 versions of FreePascal.  The SigSet type is too small.  This results 
in some signal calls overwriting other memory locations.   

I have an example program which can use the new 1.9.0 BaseUnix calls or 
libc and my definitions of the signal parameter types.  The code is 
supposed to generate a SIGALRM every second and set a boolean every time 
it does.  Depending on other unrelated code added to the program, it will 
not respond to SIGALRM at all, or it will respond too often as if the 
signal was sent to the program over and over in a tight loop.

And of course, since this is my first post, I would like to thank all 
the developers for their fine work!  I have been slowly replacing 
libraries and applications I had written in Java with FreePascal versions.
Other than this signal issue, I haven't had a single problem with the 
compiler or libraries.  Everything seems rock solid!  Thanks again.


program SigTest;

{$LINKLIB libc}
uses
   BaseUnix;
//   systhrds;

// Ordinal types
type
   int8   = shortint;
   int16  = smallint;
   int32  = longint;
   word8  = byte;
   word16 = word;
   word32 = cardinal;
   word64 = qword;
   size_t = int32; // Used by many standard C calls


// *************************************************************************
// * Structurs and variables used for Linux signal handling calls.
// *************************************************************************

const
   SI_PAD_SIZE = 128;  // Only works for 32 bit architecture!
type
   sigset_t_ptr = ^sigset_t;
   sigset_t = array[ 0..127] of byte;

   sigval_t = record
      case word8 of
         0: ( ival_int: word32);
         1: ( sival_ptr: pointer);
      end; // sigval_t record

   siginfo_t = record
         case word8 of
            0: (_pad: array[ 0..SI_PAD_SIZE - 1] of word8);
            1: ( si_pid: int32;
                 si_uid: word32;
                 case word8 of
                    1: ( si_sigval: sigval_t);
                    2: ( si_status: int32;
                         si_utime:  int32;
                         si_stime:  int32);  // SIGCHILD
                 ); // case
            2: ( _timer1: word32;
                 _timer2: word32);  // timer (SIGALRM?)
            3: ( si_addr: pointer); // faults
            4: ( si_band: int32;
                 si_fd:   int32);   // SIGPOLL
      end; // siginfo_t


   // A signal handler which just recieves the signal number
   SignalHandlerProc = procedure( SignalNumber: int32);

   // A signal handler which recieves more information about the signal
   SignalActionProc = procedure( SignalNumber: int32;
                                 var SigInfo:  siginfo_t;
                                 var Unknown);

   // Used to set signal behaviour using the sigaction() call
   sa_procType = record
         case word8 of
            0:  (sa_handler:   SignalHandlerProc);
            1:  (sa_sigaction: SignalActionProc);
      end; // sa_procType

   SignalActionRecPtr = ^SignalActionRec;
   SignalActionRec = record
         sa_proc:      sa_procType;
         sa_mask:      sigset_t;
         sa_flags:     int32;
         sa_restorer:  pointer;
      end; // SignalActionRec



// *************************************************************************
// * External GLIBC Functions
// *************************************************************************

function sigemptyset( var SignalSet: sigset_t): int32; cdecl; external;
function sigfillset(  var SignalSet: sigset_t): int32; cdecl; external;
function sigaddset(   var SignalSet: sigset_t; SignalNumber: int32): int32;
                                                            cdecl; external;
function sigdelset(   var SignalSet: sigset_t; SignalNumber: int32): int32;
                                                            cdecl; external;
function sigismember( var SignalSet: sigset_t; SignalNumber: int32): int32;
                                                            cdecl; external;
function sigaction( SignalNumber:  word32;
                    NewAction:     SignalActionRecPtr;
                    OldAction:     SignalActionRecPtr): int32; cdecl; external;
function sigprocmask( How:    int32;
                      OldSet: sigset_t_ptr;
                      NewSet: sigset_t_ptr): int32; cdecl; external;
function sigpending( var Mask: sigset_t): int32; cdecl; external;
function sigsuspend( var Mask: sigset_t): int32; cdecl; external;


// *************************************************************************
// * AlrmSigHandler() - Handle Alrm signals
// *************************************************************************

var
   AlarmRecieved: boolean;

procedure AlrmSigHandler( Sig: LongInt); cdecl;
   begin
      AlarmRecieved:= true;
      writeln( 'AlrmSigHandler(): Alarm recieved');
   end; // AlrmSigHandler()


// *************************************************************************
// * MyInstallAlrmSignalHandler() - Install our signal handler
// *************************************************************************

procedure MyInstallAlrmSignalHandler();
   var
      NewAction:  SignalActionRec;
      OldAction:  SignalActionRec;
      NewSigSet:  sigset_t;
   begin
      SigAction( SIGALRM, nil, @OldAction);
      NewAction:= OldAction;
      NewAction.sa_proc.sa_handler:= @AlrmSigHandler;

      // Install the signal handler
      SigAction( SIGALRM, @NewAction, nil);

      // Make sure the signal is not blocked
      SigEmptySet( NewSigSet);
      SigAddSet( NewSigSet, SIGALRM);
      SigProcMask( SIG_UNBLOCK, @NewSigSet, nil);
   end; // MyInstallAlrmSignalHandler()


// *************************************************************************
// * MySignalLoop()
// *************************************************************************

procedure MySignalLoop();
   var
      MySigMask: SigSet_t;
      i:         integer;
   begin
      AlarmRecieved:= false;
      fpAlarm( 1);

      // Create a zeroed signal mask so we can recieve all signals
      for i:= 0 to 127 do begin
         MySigMask[ i]:= 0;
      end;
//      sigemptyset( MySigMask);

      while( true) do begin
         SigSuspend( MySigMask);
         if( AlarmRecieved) then begin
            fpAlarm( 1);
            AlarmRecieved:= false;

            writeln( 'Recieved a SIGALRM!');
         end; // if AlarmRecieved
      end;
   end; // MySignalLoop()


// *************************************************************************
// * NewInstallAlrmSignalHandler() - Install our signal handler
// *************************************************************************

procedure NewInstallAlrmSignalHandler();
   var
      NewAction:  SigActionRec;
      OldAction:  SigActionRec;
      NewSigSet:  SigSet;
   begin
      fpSigAction( SIGALRM, nil, @OldAction);
      NewAction:= OldAction;
      NewAction.sa_handler:= @AlrmSigHandler;

      // Install the signal handler
      fpSigAction( SIGALRM, @NewAction, nil);

      // Make sure the signal is not blocked
      fpSigEmptySet( NewSigSet);
      fpSigAddSet( NewSigSet, SIGALRM);
      fpSigProcMask( SIG_UNBLOCK, @NewSigSet, nil);
   end; // NewInstallAlrmSignalHandler()


// *************************************************************************
// * NewSignalLoop()
// *************************************************************************

procedure NewSignalLoop();
   var
      MySigMask: SigSet;
      i:         integer;
   begin
      AlarmRecieved:= false;
      fpAlarm( 1);
      // Create a zeroed signal mask so we can recieve all signals
      for i:= 0 to wordsinsigset - 1 do begin
         MySigMask[ i]:= 0;
      end;

      while( true) do begin
         fpSigSuspend( MySigMask);
         if( AlarmRecieved) then begin
            fpAlarm( 1);
            AlarmRecieved:= false;

            writeln( 'Recieved a SIGALRM!');
         end; // if AlarmRecieved
      end;
   end; // NewSignalLoop()


// *************************************************************************
// * main()
// *************************************************************************
const
   UseNew = true;
begin
   if( UseNew) then begin
      NewInstallAlrmSignalHandler();
      NewSignalLoop();
   end else begin
      MyInstallAlrmSignalHandler();
      MySignalLoop();
   end;
end.






More information about the fpc-devel mailing list