1 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 2 /* */ 3 /* This file is part of the program and library */ 4 /* SCIP --- Solving Constraint Integer Programs */ 5 /* */ 6 /* Copyright (c) 2002-2023 Zuse Institute Berlin (ZIB) */ 7 /* */ 8 /* Licensed under the Apache License, Version 2.0 (the "License"); */ 9 /* you may not use this file except in compliance with the License. */ 10 /* You may obtain a copy of the License at */ 11 /* */ 12 /* http://www.apache.org/licenses/LICENSE-2.0 */ 13 /* */ 14 /* Unless required by applicable law or agreed to in writing, software */ 15 /* distributed under the License is distributed on an "AS IS" BASIS, */ 16 /* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */ 17 /* See the License for the specific language governing permissions and */ 18 /* limitations under the License. */ 19 /* */ 20 /* You should have received a copy of the Apache-2.0 license */ 21 /* along with SCIP; see the file LICENSE. If not visit scipopt.org. */ 22 /* */ 23 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 24 25 /**@file interrupt.c 26 * @ingroup OTHER_CFILES 27 * @brief methods and datastructures for catching the user CTRL-C interrupt 28 * @author Tobias Achterberg 29 */ 30 31 /*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/ 32 33 #include <assert.h> 34 #include <sys/types.h> 35 #include <stdlib.h> 36 #include <signal.h> 37 38 #include "scip/def.h" 39 #include "scip/pub_message.h" 40 #include "blockmemshell/memory.h" 41 #include "scip/interrupt.h" 42 43 44 static volatile 45 int ninterrupts = 0; /**< static variable counting the number of CTRL-C interrupts */ 46 static volatile 47 int nterms = 0; /**< static variable counting the number of times that the process received a SIGTERM signal */ 48 49 50 #ifdef SCIP_NO_SIGACTION 51 typedef void (*SigHdlr)(int); 52 53 /** CTRL-C interrupt data */ 54 struct SCIP_Interrupt 55 { 56 SigHdlr oldsighdlr; /**< old CTRL-C interrupt handler */ 57 int nuses; /**< number of times, the interrupt is captured */ 58 }; 59 60 #else 61 62 /** CTRL-C interrupt data */ 63 struct SCIP_Interrupt 64 { 65 struct sigaction oldsigaction; /**< old CTRL-C interrupt handler */ 66 int nuses; /**< number of times, the interrupt is captured */ 67 }; 68 #endif 69 70 /** interrupt handler for CTRL-C interrupts */ 71 static 72 void interruptHandler( 73 int signum /**< interrupt signal number */ 74 ) 75 { 76 SCIP_UNUSED(signum); 77 78 ninterrupts++; 79 if( ninterrupts >= 5 ) 80 { 81 printf("pressed CTRL-C %d times. forcing termination.\n", ninterrupts); 82 exit(1); 83 } 84 else 85 { 86 printf("pressed CTRL-C %d times (5 times for forcing termination)\n", ninterrupts); 87 } 88 } 89 90 /** creates a CTRL-C interrupt data */ 91 SCIP_RETCODE SCIPinterruptCreate( 92 SCIP_INTERRUPT** interrupt /**< pointer to store the CTRL-C interrupt data */ 93 ) 94 { 95 assert(interrupt != NULL); 96 97 SCIP_ALLOC( BMSallocMemory(interrupt) ); 98 (*interrupt)->nuses = 0; 99 100 return SCIP_OKAY; 101 } 102 103 /** frees a CTRL-C interrupt data */ 104 void SCIPinterruptFree( 105 SCIP_INTERRUPT** interrupt /**< pointer to the CTRL-C interrupt data */ 106 ) 107 { 108 assert(interrupt != NULL); 109 110 BMSfreeMemory(interrupt); 111 } 112 113 /** captures the CTRL-C interrupt to call the SCIP's own interrupt handler */ 114 void SCIPinterruptCapture( 115 SCIP_INTERRUPT* interrupt /**< CTRL-C interrupt data */ 116 ) 117 { 118 assert(interrupt != NULL); 119 assert(interrupt->nuses >= 0); 120 121 if( interrupt->nuses == 0 ) 122 { 123 #ifdef SCIP_NO_SIGACTION 124 interrupt->oldsighdlr = signal(SIGINT, interruptHandler); 125 #else 126 struct sigaction newaction; 127 128 /* initialize new signal action */ 129 newaction.sa_handler = interruptHandler; 130 newaction.sa_flags = 0; 131 (void)sigemptyset(&newaction.sa_mask); 132 133 /* set new signal action, and remember old one */ 134 (void)sigaction(SIGINT, &newaction, &interrupt->oldsigaction); 135 #endif 136 137 ninterrupts = 0; 138 nterms = 0; 139 } 140 interrupt->nuses++; 141 } 142 143 /** releases the CTRL-C interrupt and restores the old interrupt handler */ 144 void SCIPinterruptRelease( 145 SCIP_INTERRUPT* interrupt /**< CTRL-C interrupt data */ 146 ) 147 { 148 assert(interrupt != NULL); 149 assert(interrupt->nuses >= 1); 150 151 interrupt->nuses--; 152 if( interrupt->nuses == 0 ) 153 { 154 #ifdef SCIP_NO_SIGACTION 155 (void)signal(SIGINT, interrupt->oldsighdlr); 156 #else 157 (void)sigaction(SIGINT, &interrupt->oldsigaction, NULL); 158 #endif 159 } 160 } 161 162 /** returns whether the user interrupted by pressing CTRL-C */ 163 SCIP_Bool SCIPinterrupted( 164 void 165 ) 166 { 167 return (ninterrupts > 0); 168 } 169 170 /** returns whether a process termination signal was received */ 171 SCIP_Bool SCIPterminated( 172 void 173 ) 174 { 175 return (nterms > 0); 176 } 177 178 /** sends a termination signal to all SCIP processes so that they try to terminate as soon as possible 179 * 180 * @note For terminating a specific SCIP process use SCIPinterruptSolve(). 181 */ 182 void SCIPtryTerminate( 183 void 184 ) 185 { 186 nterms++; 187 } 188 189 /** resets the number of interrupts to 0 */ 190 void SCIPresetInterrupted( 191 void 192 ) 193 { 194 ninterrupts = 0; 195 nterms = 0; 196 } 197 198