8
8
*
9
9
*
10
10
* 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 $
12
12
*
13
13
*-------------------------------------------------------------------------
14
14
*/
52
52
#include "storage/sinval.h"
53
53
#include "storage/spin.h"
54
54
55
-
56
55
int DeadlockTimeout = 1000 ;
56
+ int StatementTimeout = 0 ;
57
+ int RemainingStatementTimeout = 0 ;
58
+ bool alarm_is_statement_timeout = false;
57
59
58
60
PGPROC * MyProc = NULL ;
59
61
@@ -319,7 +321,7 @@ LockWaitCancel(void)
319
321
waitingForLock = false;
320
322
321
323
/* Turn off the deadlock timer, if it's still running (see ProcSleep) */
322
- disable_sigalrm_interrupt ( );
324
+ disable_sig_alarm (false );
323
325
324
326
/* Unlink myself from the wait queue, if on it (might not be anymore!) */
325
327
LWLockAcquire (LockMgrLock ,LW_EXCLUSIVE );
@@ -600,7 +602,7 @@ ProcSleep(LOCKMETHODTABLE *lockMethodTable,
600
602
601
603
/*
602
604
* 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
604
606
* release the semaphore since we haven't tried to lock it yet.
605
607
*/
606
608
if (early_deadlock )
@@ -632,13 +634,13 @@ ProcSleep(LOCKMETHODTABLE *lockMethodTable,
632
634
* By delaying the check until we've waited for a bit, we can avoid
633
635
* running the rather expensive deadlock-check code in most cases.
634
636
*/
635
- if (!enable_sigalrm_interrupt (DeadlockTimeout ))
637
+ if (!enable_sig_alarm (DeadlockTimeout , false ))
636
638
elog (FATAL ,"ProcSleep: Unable to set timer for process wakeup" );
637
639
638
640
/*
639
641
* If someone wakes us between LWLockRelease and PGSemaphoreLock,
640
642
* 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
642
644
* invoked but does not detect a deadlock, PGSemaphoreLock() will
643
645
* continue to wait. There used to be a loop here, but it was useless
644
646
* code...
@@ -654,7 +656,7 @@ ProcSleep(LOCKMETHODTABLE *lockMethodTable,
654
656
/*
655
657
* Disable the timer, if it's still running
656
658
*/
657
- if (!disable_sigalrm_interrupt ( ))
659
+ if (!disable_sig_alarm (false ))
658
660
elog (FATAL ,"ProcSleep: Unable to disable timer for process wakeup" );
659
661
660
662
/*
@@ -785,7 +787,7 @@ ProcLockWakeup(LOCKMETHODTABLE *lockMethodTable, LOCK *lock)
785
787
* --------------------
786
788
*/
787
789
void
788
- HandleDeadLock ( SIGNAL_ARGS )
790
+ CheckDeadLock ( void )
789
791
{
790
792
int save_errno = errno ;
791
793
@@ -921,52 +923,180 @@ ProcSendSignal(BackendId procId)
921
923
* Delay is given in milliseconds.Caller should be sure a SIGALRM
922
924
* signal handler is installed before this is called.
923
925
*
926
+ * This code properly handles multiple alarms when the statement_timeout
927
+ * alarm is specified first.
928
+ *
924
929
* Returns TRUE if okay, FALSE on failure.
925
930
*/
926
931
bool
927
- enable_sigalrm_interrupt (int delayms )
932
+ enable_sig_alarm (int delayms , bool is_statement_timeout )
928
933
{
929
934
#ifndef __BEOS__
930
- struct itimerval timeval ,
931
- dummy ;
935
+ struct itimerval timeval ,remaining ;
936
+ #else
937
+ bigtime_t time_interval ,remaining ;
938
+ #endif
932
939
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__
933
947
MemSet (& timeval ,0 ,sizeof (struct itimerval ));
934
948
timeval .it_value .tv_sec = delayms /1000 ;
935
949
timeval .it_value .tv_usec = (delayms %1000 )* 1000 ;
936
- if (setitimer (ITIMER_REAL ,& timeval ,& dummy ))
950
+ if (setitimer (ITIMER_REAL ,& timeval ,& remaining ))
937
951
return false;
938
952
#else
939
953
/* BeOS doesn't have setitimer, but has set_alarm */
940
- bigtime_t time_interval ;
941
-
942
954
time_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 )
944
956
return false;
945
957
#endif
946
958
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
+
947
1010
return true;
948
1011
}
949
1012
950
1013
/*
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.
952
1018
*
953
1019
* Returns TRUE if okay, FALSE on failure.
954
1020
*/
955
1021
bool
956
- disable_sigalrm_interrupt ( void )
1022
+ disable_sig_alarm ( bool is_statement_timeout )
957
1023
{
958
1024
#ifndef __BEOS__
959
- struct itimerval timeval ,
960
- dummy ;
961
-
1025
+ struct itimerval timeval ,remaining ;
962
1026
MemSet (& timeval ,0 ,sizeof (struct itimerval ));
963
- if (setitimer (ITIMER_REAL ,& timeval ,& dummy ))
964
- return false;
965
1027
#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 ;
969
1029
#endif
970
1030
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
+
971
1079
return true;
972
1080
}
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
+