88 *
99 *
1010 * IDENTIFICATION
11- * $Header: /cvsroot/pgsql/src/backend/storage/lmgr/proc.c,v 1.121 2002/06/20 20:29:35 momjian Exp $
11+ * $Header: /cvsroot/pgsql/src/backend/storage/lmgr/proc.c,v 1.122 2002/07/13 01:02:14 momjian Exp $
1212 *
1313 *-------------------------------------------------------------------------
1414 */
5252#include "storage/sinval.h"
5353#include "storage/spin.h"
5454
55-
5655int DeadlockTimeout = 1000 ;
56+ int StatementTimeout = 0 ;
57+ int RemainingStatementTimeout = 0 ;
58+ bool alarm_is_statement_timeout = false;
5759
5860PGPROC * MyProc = NULL ;
5961
@@ -319,7 +321,7 @@ LockWaitCancel(void)
319321waitingForLock = false;
320322
321323/* Turn off the deadlock timer, if it's still running (see ProcSleep) */
322- disable_sigalrm_interrupt ( );
324+ disable_sig_alarm (false );
323325
324326/* Unlink myself from the wait queue, if on it (might not be anymore!) */
325327LWLockAcquire (LockMgrLock ,LW_EXCLUSIVE );
@@ -600,7 +602,7 @@ ProcSleep(LOCKMETHODTABLE *lockMethodTable,
600602
601603/*
602604 * If we detected deadlock, give up without waiting. This must agree
603- * withHandleDeadLock 's recovery code, except that we shouldn't
605+ * withCheckDeadLock 's recovery code, except that we shouldn't
604606 * release the semaphore since we haven't tried to lock it yet.
605607 */
606608if (early_deadlock )
@@ -632,13 +634,13 @@ ProcSleep(LOCKMETHODTABLE *lockMethodTable,
632634 * By delaying the check until we've waited for a bit, we can avoid
633635 * running the rather expensive deadlock-check code in most cases.
634636 */
635- if (!enable_sigalrm_interrupt (DeadlockTimeout ))
637+ if (!enable_sig_alarm (DeadlockTimeout , false ))
636638elog (FATAL ,"ProcSleep: Unable to set timer for process wakeup" );
637639
638640/*
639641 * If someone wakes us between LWLockRelease and PGSemaphoreLock,
640642 * PGSemaphoreLock will not block. The wakeup is "saved" by the
641- * semaphore implementation. Note also that ifHandleDeadLock is
643+ * semaphore implementation. Note also that ifCheckDeadLock is
642644 * invoked but does not detect a deadlock, PGSemaphoreLock() will
643645 * continue to wait. There used to be a loop here, but it was useless
644646 * code...
@@ -654,7 +656,7 @@ ProcSleep(LOCKMETHODTABLE *lockMethodTable,
654656/*
655657 * Disable the timer, if it's still running
656658 */
657- if (!disable_sigalrm_interrupt ( ))
659+ if (!disable_sig_alarm (false ))
658660elog (FATAL ,"ProcSleep: Unable to disable timer for process wakeup" );
659661
660662/*
@@ -785,7 +787,7 @@ ProcLockWakeup(LOCKMETHODTABLE *lockMethodTable, LOCK *lock)
785787 * --------------------
786788 */
787789void
788- HandleDeadLock ( SIGNAL_ARGS )
790+ CheckDeadLock ( void )
789791{
790792int save_errno = errno ;
791793
@@ -921,52 +923,180 @@ ProcSendSignal(BackendId procId)
921923 * Delay is given in milliseconds.Caller should be sure a SIGALRM
922924 * signal handler is installed before this is called.
923925 *
926+ * This code properly handles multiple alarms when the statement_timeout
927+ * alarm is specified first.
928+ *
924929 * Returns TRUE if okay, FALSE on failure.
925930 */
926931bool
927- enable_sigalrm_interrupt (int delayms )
932+ enable_sig_alarm (int delayms , bool is_statement_timeout )
928933{
929934#ifndef __BEOS__
930- struct itimerval timeval ,
931- dummy ;
935+ struct itimerval timeval ,remaining ;
936+ #else
937+ bigtime_t time_interval ,remaining ;
938+ #endif
932939
940+ /* Don't set timer if the statement timeout scheduled before next alarm. */
941+ if (alarm_is_statement_timeout &&
942+ !is_statement_timeout &&
943+ RemainingStatementTimeout <=delayms )
944+ return true;
945+
946+ #ifndef __BEOS__
933947MemSet (& timeval ,0 ,sizeof (struct itimerval ));
934948timeval .it_value .tv_sec = delayms /1000 ;
935949timeval .it_value .tv_usec = (delayms %1000 )* 1000 ;
936- if (setitimer (ITIMER_REAL ,& timeval ,& dummy ))
950+ if (setitimer (ITIMER_REAL ,& timeval ,& remaining ))
937951return false;
938952#else
939953/* BeOS doesn't have setitimer, but has set_alarm */
940- bigtime_t time_interval ;
941-
942954time_interval = delayms * 1000 ;/* usecs */
943- if (set_alarm (time_interval ,B_ONE_SHOT_RELATIVE_ALARM )< 0 )
955+ if (( remaining = set_alarm (time_interval ,B_ONE_SHOT_RELATIVE_ALARM ) )< 0 )
944956return false;
945957#endif
946958
959+ if (is_statement_timeout )
960+ RemainingStatementTimeout = StatementTimeout ;
961+ else
962+ {
963+ /* Switching to non-statement-timeout alarm, get remaining time */
964+ if (alarm_is_statement_timeout )
965+ {
966+ #ifndef __BEOS__
967+ /* We lose precision here because we convert to milliseconds */
968+ RemainingStatementTimeout = remaining .it_value .tv_sec * 1000 +
969+ remaining .it_value .tv_usec /1000 ;
970+ #else
971+ RemainingStatementTimeout = remaining /1000 ;
972+ #endif
973+ /* Rounding could cause a zero */
974+ if (RemainingStatementTimeout == 0 )
975+ RemainingStatementTimeout = 1 ;
976+ }
977+
978+ if (RemainingStatementTimeout )
979+ {
980+ /* Remaining timeout alarm < delayms? */
981+ if (RemainingStatementTimeout <=delayms )
982+ {
983+ /* reinstall statement timeout alarm */
984+ alarm_is_statement_timeout = true;
985+ #ifndef __BEOS__
986+ remaining .it_value .tv_sec = RemainingStatementTimeout /1000 ;
987+ remaining .it_value .tv_usec = (RemainingStatementTimeout %1000 )* 1000 ;
988+ if (setitimer (ITIMER_REAL ,& remaining ,& timeval ))
989+ return false;
990+ else
991+ return true;
992+ #else
993+ remaining = RemainingStatementTimeout * 1000 ;
994+ if ((timeval = set_alarm (remaining ,B_ONE_SHOT_RELATIVE_ALARM ))< 0 )
995+ return false;
996+ else
997+ return true;
998+ #endif
999+ }
1000+ else
1001+ RemainingStatementTimeout -= delayms ;
1002+ }
1003+ }
1004+
1005+ if (is_statement_timeout )
1006+ alarm_is_statement_timeout = true;
1007+ else
1008+ alarm_is_statement_timeout = false;
1009+
9471010return true;
9481011}
9491012
9501013/*
951- * Disable the SIGALRM interrupt, if it has not yet fired
1014+ * Cancel the SIGALRM timer.
1015+ *
1016+ * This is also called if the timer has fired to reschedule
1017+ * the statement_timeout timer.
9521018 *
9531019 * Returns TRUE if okay, FALSE on failure.
9541020 */
9551021bool
956- disable_sigalrm_interrupt ( void )
1022+ disable_sig_alarm ( bool is_statement_timeout )
9571023{
9581024#ifndef __BEOS__
959- struct itimerval timeval ,
960- dummy ;
961-
1025+ struct itimerval timeval ,remaining ;
9621026MemSet (& timeval ,0 ,sizeof (struct itimerval ));
963- if (setitimer (ITIMER_REAL ,& timeval ,& dummy ))
964- return false;
9651027#else
966- /* BeOS doesn't have setitimer, but has set_alarm */
967- if (set_alarm (B_INFINITE_TIMEOUT ,B_PERIODIC_ALARM )< 0 )
968- return false;
1028+ bigtime_t time_interval = 0 ;
9691029#endif
9701030
1031+ if (!is_statement_timeout && RemainingStatementTimeout )
1032+ {
1033+ #ifndef __BEOS__
1034+ /* turn off timer and get remaining time, if any */
1035+ if (setitimer (ITIMER_REAL ,& timeval ,& remaining ))
1036+ return false;
1037+ /* Add remaining time back because the timer didn't complete */
1038+ RemainingStatementTimeout += remaining .it_value .tv_sec * 1000 +
1039+ remaining .it_value .tv_usec /1000 ;
1040+ /* Prepare to set timer */
1041+ timeval .it_value .tv_sec = RemainingStatementTimeout /1000 ;
1042+ timeval .it_value .tv_usec = (RemainingStatementTimeout %1000 )* 1000 ;
1043+ #else
1044+ /* BeOS doesn't have setitimer, but has set_alarm */
1045+ if ((time_interval = set_alarm (B_INFINITE_TIMEOUT ,B_PERIODIC_ALARM ))< 0 )
1046+ return false;
1047+ RemainingStatementTimeout += time_interval /1000 ;
1048+ time_interval = RemainingStatementTimeout * 1000 ;
1049+ #endif
1050+ /* Restore remaining statement timeout value */
1051+ alarm_is_statement_timeout = true;
1052+ }
1053+ /*
1054+ *Optimization: is_statement_timeout && RemainingStatementTimeout == 0
1055+ * does nothing. This is for cases where no timeout was set.
1056+ */
1057+ if (!is_statement_timeout || RemainingStatementTimeout )
1058+ {
1059+ #ifndef __BEOS__
1060+ if (setitimer (ITIMER_REAL ,& timeval ,& remaining ))
1061+ return false;
1062+ #else
1063+ if (time_interval )
1064+ {
1065+ if (set_alarm (time_interval ,B_ONE_SHOT_RELATIVE_ALARM )< 0 )
1066+ return false;
1067+ }
1068+ else
1069+ {
1070+ if (set_alarm (B_INFINITE_TIMEOUT ,B_PERIODIC_ALARM )< 0 )
1071+ return false;
1072+ }
1073+ #endif
1074+ }
1075+
1076+ if (is_statement_timeout )
1077+ RemainingStatementTimeout = 0 ;
1078+
9711079return true;
9721080}
1081+
1082+
1083+ /*
1084+ * Call alarm handler, either StatementCancel or Deadlock checker.
1085+ */
1086+ void
1087+ handle_sig_alarm (SIGNAL_ARGS )
1088+ {
1089+ if (alarm_is_statement_timeout )
1090+ {
1091+ RemainingStatementTimeout = 0 ;
1092+ alarm_is_statement_timeout = false;
1093+ kill (MyProcPid ,SIGINT );
1094+ }
1095+ else
1096+ {
1097+ CheckDeadLock ();
1098+ /* Reactivate any statement_timeout alarm. */
1099+ disable_sig_alarm (false);
1100+ }
1101+ }
1102+