Fossil SCM
Improved windows code for the backoffice. Properly check to see if processes still exist. Provide a timeout feature.
Commit
43c29877be3939b16a5abcf5be925a15c7b44382f8752bcc2b11f23d6ba62ef8
Parent
2583cae18a4bcf0…
2 files changed
+94
-14
+94
-14
+94
-14
| --- src/backoffice.c | ||
| +++ src/backoffice.c | ||
| @@ -62,14 +62,16 @@ | ||
| 62 | 62 | #include <time.h> |
| 63 | 63 | #if defined(_WIN32) |
| 64 | 64 | # include <windows.h> |
| 65 | 65 | # include <stdio.h> |
| 66 | 66 | # include <process.h> |
| 67 | +# define GETPID (int)GetCurrentProcessId | |
| 67 | 68 | #else |
| 68 | 69 | # include <unistd.h> |
| 69 | 70 | # include <sys/types.h> |
| 70 | 71 | # include <signal.h> |
| 72 | +# define GETPID getpid | |
| 71 | 73 | #endif |
| 72 | 74 | |
| 73 | 75 | /* |
| 74 | 76 | ** The BKOFCE_LEASE_TIME is the amount of time for which a single backoffice |
| 75 | 77 | ** processing run is valid. Each backoffice run monopolizes the lease for |
| @@ -125,10 +127,27 @@ | ||
| 125 | 127 | ** longer than needed. |
| 126 | 128 | */ |
| 127 | 129 | void backoffice_no_delay(void){ |
| 128 | 130 | backofficeNoDelay = 1; |
| 129 | 131 | } |
| 132 | + | |
| 133 | +/* | |
| 134 | +** Sleeps for the specified number of milliseconds -OR- until interrupted | |
| 135 | +** by another thread (if supported by the underlying platform). Non-zero | |
| 136 | +** will be returned if the sleep was interrupted. | |
| 137 | +*/ | |
| 138 | +static int backofficeSleep(int milliseconds){ | |
| 139 | +#if defined(_WIN32) | |
| 140 | + assert( milliseconds>=0 ); | |
| 141 | + if( SleepEx((DWORD)milliseconds, TRUE)==WAIT_IO_COMPLETION ){ | |
| 142 | + return 1; | |
| 143 | + } | |
| 144 | +#else | |
| 145 | + sqlite3_sleep(milliseconds); | |
| 146 | +#endif | |
| 147 | + return 0; | |
| 148 | +} | |
| 130 | 149 | |
| 131 | 150 | /* |
| 132 | 151 | ** Parse a unsigned 64-bit integer from a string. Return a pointer |
| 133 | 152 | ** to the character of z[] that occurs after the integer. |
| 134 | 153 | */ |
| @@ -170,17 +189,35 @@ | ||
| 170 | 189 | " VALUES('backoffice','%lld %lld %lld %lld',now())", |
| 171 | 190 | pLease->idCurrent, pLease->tmCurrent, |
| 172 | 191 | pLease->idNext, pLease->tmNext); |
| 173 | 192 | } |
| 174 | 193 | |
| 194 | +/* | |
| 195 | +** Check to see if the specified Win32 process is still alive. It | |
| 196 | +** should be noted that even if this function returns non-zero, the | |
| 197 | +** process may die before another operation on it can be completed. | |
| 198 | +*/ | |
| 199 | +#if defined(_WIN32) | |
| 200 | +#ifndef PROCESS_QUERY_LIMITED_INFORMATION | |
| 201 | +# define PROCESS_QUERY_LIMITED_INFORMATION (0x1000) | |
| 202 | +#endif | |
| 203 | +static int backofficeWin32ProcessExists(DWORD dwProcessId){ | |
| 204 | + HANDLE hProcess; | |
| 205 | + hProcess = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION,FALSE,dwProcessId); | |
| 206 | + if( hProcess==NULL ) return 0; | |
| 207 | + CloseHandle(hProcess); | |
| 208 | + return 1; | |
| 209 | +} | |
| 210 | +#endif | |
| 211 | + | |
| 175 | 212 | /* |
| 176 | 213 | ** Check to see if the process identified by pid is alive. If |
| 177 | 214 | ** we cannot prove the the process is dead, return true. |
| 178 | 215 | */ |
| 179 | 216 | static int backofficeProcessExists(sqlite3_uint64 pid){ |
| 180 | 217 | #if defined(_WIN32) |
| 181 | - return 1; | |
| 218 | + return pid>0 && backofficeWin32ProcessExists((DWORD)pid)!=0; | |
| 182 | 219 | #else |
| 183 | 220 | return pid>0 && kill((pid_t)pid, 0)==0; |
| 184 | 221 | #endif |
| 185 | 222 | } |
| 186 | 223 | |
| @@ -188,39 +225,65 @@ | ||
| 188 | 225 | ** Check to see if the process identified by pid has finished. If |
| 189 | 226 | ** we cannot prove the the process is still running, return true. |
| 190 | 227 | */ |
| 191 | 228 | static int backofficeProcessDone(sqlite3_uint64 pid){ |
| 192 | 229 | #if defined(_WIN32) |
| 193 | - return 1; | |
| 230 | + return pid<=0 || backofficeWin32ProcessExists((DWORD)pid)==0; | |
| 194 | 231 | #else |
| 195 | 232 | return pid<=0 || kill((pid_t)pid, 0)!=0; |
| 196 | 233 | #endif |
| 197 | 234 | } |
| 198 | 235 | |
| 199 | 236 | /* |
| 200 | 237 | ** Return a process id number for the current process |
| 201 | 238 | */ |
| 202 | 239 | static sqlite3_uint64 backofficeProcessId(void){ |
| 203 | -#if defined(_WIN32) | |
| 204 | - return (sqlite3_uint64)GetCurrentProcessId(); | |
| 205 | -#else | |
| 206 | - return (sqlite3_uint64)getpid(); | |
| 207 | -#endif | |
| 240 | + return (sqlite3_uint64)GETPID(); | |
| 208 | 241 | } |
| 209 | 242 | |
| 210 | 243 | /* |
| 211 | 244 | ** Set an alarm to cause the process to exit after "x" seconds. This |
| 212 | 245 | ** prevents any kind of bug from keeping a backoffice process running |
| 213 | 246 | ** indefinitely. |
| 214 | 247 | */ |
| 215 | -#if !defined(_WIN32) | |
| 216 | 248 | static void backofficeSigalrmHandler(int x){ |
| 217 | - fossil_panic("backoffice timeout"); | |
| 249 | + fossil_panic("backoffice timeout (%d seconds)", x); | |
| 250 | +} | |
| 251 | +#if defined(_WIN32) | |
| 252 | +static void *threadHandle = NULL; | |
| 253 | +static void __stdcall backofficeWin32NoopApcProc(ULONG_PTR pArg){} /* NO-OP */ | |
| 254 | +static void backofficeWin32ThreadCleanup(){ | |
| 255 | + if( threadHandle!=NULL ){ | |
| 256 | + /* Queue no-op asynchronous procedure call to the sleeping | |
| 257 | + * thread. This will cause it to wake up with a non-zero | |
| 258 | + * return value. */ | |
| 259 | + if( QueueUserAPC(backofficeWin32NoopApcProc, threadHandle, 0) ){ | |
| 260 | + /* Wait for the thread to wake up and then exit. */ | |
| 261 | + WaitForSingleObject(threadHandle, INFINITE); | |
| 262 | + } | |
| 263 | + CloseHandle(threadHandle); | |
| 264 | + threadHandle = NULL; | |
| 265 | + } | |
| 266 | +} | |
| 267 | +static unsigned __stdcall backofficeWin32SigalrmThreadProc( | |
| 268 | + void *pArg /* IN: Pointer to integer number of whole seconds. */ | |
| 269 | +){ | |
| 270 | + int seconds = FOSSIL_PTR_TO_INT(pArg); | |
| 271 | + if( SleepEx((DWORD)seconds * 1000, TRUE)==0 ){ | |
| 272 | + backofficeSigalrmHandler(seconds); | |
| 273 | + } | |
| 274 | + _endthreadex(0); | |
| 275 | + return 0; /* NOT REACHED */ | |
| 218 | 276 | } |
| 219 | 277 | #endif |
| 220 | 278 | static void backofficeTimeout(int x){ |
| 221 | -#if !defined(_WIN32) | |
| 279 | +#if defined(_WIN32) | |
| 280 | + backofficeWin32ThreadCleanup(); | |
| 281 | + threadHandle = (void*)_beginthreadex( | |
| 282 | + 0, 0, backofficeWin32SigalrmThreadProc, FOSSIL_INT_TO_PTR(x), 0, 0 | |
| 283 | + ); | |
| 284 | +#else | |
| 222 | 285 | signal(SIGALRM, backofficeSigalrmHandler); |
| 223 | 286 | alarm(x); |
| 224 | 287 | #endif |
| 225 | 288 | } |
| 226 | 289 | |
| @@ -334,11 +397,11 @@ | ||
| 334 | 397 | x.tmNext = 0; |
| 335 | 398 | backofficeWriteLease(&x); |
| 336 | 399 | db_end_transaction(0); |
| 337 | 400 | if( g.fAnyTrace ){ |
| 338 | 401 | fprintf(stderr, "/***** Begin Backoffice Processing %d *****/\n", |
| 339 | - getpid()); | |
| 402 | + GETPID()); | |
| 340 | 403 | } |
| 341 | 404 | backoffice_work(); |
| 342 | 405 | break; |
| 343 | 406 | } |
| 344 | 407 | if( backofficeNoDelay || db_get_boolean("backoffice-nodelay",1) ){ |
| @@ -353,25 +416,42 @@ | ||
| 353 | 416 | x.idNext = idSelf; |
| 354 | 417 | x.tmNext = (tmNow>x.tmCurrent ? tmNow : x.tmCurrent) + BKOFCE_LEASE_TIME; |
| 355 | 418 | backofficeWriteLease(&x); |
| 356 | 419 | db_end_transaction(0); |
| 357 | 420 | if( g.fAnyTrace ){ |
| 358 | - fprintf(stderr, "/***** Backoffice On-deck %d *****/\n", getpid()); | |
| 421 | + fprintf(stderr, "/***** Backoffice On-deck %d *****/\n", GETPID()); | |
| 359 | 422 | } |
| 360 | 423 | if( x.tmCurrent >= tmNow ){ |
| 361 | - sqlite3_sleep(1000*(x.tmCurrent - tmNow + 1)); | |
| 424 | + if( backofficeSleep(1000*(x.tmCurrent - tmNow + 1)) ){ | |
| 425 | + /* The sleep was interrupted by a signal from another thread. */ | |
| 426 | + if( g.fAnyTrace ){ | |
| 427 | + fprintf(stderr, "/***** Backoffice Interrupt %d *****/\n", GETPID()); | |
| 428 | + } | |
| 429 | + db_end_transaction(0); | |
| 430 | + break; | |
| 431 | + } | |
| 362 | 432 | }else{ |
| 363 | 433 | if( lastWarning+warningDelay < tmNow ){ |
| 364 | 434 | fossil_warning( |
| 365 | 435 | "backoffice process %lld still running after %d seconds", |
| 366 | 436 | x.idCurrent, (int)(BKOFCE_LEASE_TIME + tmNow - x.tmCurrent)); |
| 367 | 437 | lastWarning = tmNow; |
| 368 | 438 | warningDelay *= 2; |
| 369 | 439 | } |
| 370 | - sqlite3_sleep(1000); | |
| 440 | + if( backofficeSleep(1000) ){ | |
| 441 | + /* The sleep was interrupted by a signal from another thread. */ | |
| 442 | + if( g.fAnyTrace ){ | |
| 443 | + fprintf(stderr, "/***** Backoffice Interrupt %d *****/\n", GETPID()); | |
| 444 | + } | |
| 445 | + db_end_transaction(0); | |
| 446 | + break; | |
| 447 | + } | |
| 371 | 448 | } |
| 372 | 449 | } |
| 450 | +#if defined(_WIN32) | |
| 451 | + backofficeWin32ThreadCleanup(); | |
| 452 | +#endif | |
| 373 | 453 | return; |
| 374 | 454 | } |
| 375 | 455 | |
| 376 | 456 | /* |
| 377 | 457 | ** This routine runs to do the backoffice processing. When adding new |
| 378 | 458 |
| --- src/backoffice.c | |
| +++ src/backoffice.c | |
| @@ -62,14 +62,16 @@ | |
| 62 | #include <time.h> |
| 63 | #if defined(_WIN32) |
| 64 | # include <windows.h> |
| 65 | # include <stdio.h> |
| 66 | # include <process.h> |
| 67 | #else |
| 68 | # include <unistd.h> |
| 69 | # include <sys/types.h> |
| 70 | # include <signal.h> |
| 71 | #endif |
| 72 | |
| 73 | /* |
| 74 | ** The BKOFCE_LEASE_TIME is the amount of time for which a single backoffice |
| 75 | ** processing run is valid. Each backoffice run monopolizes the lease for |
| @@ -125,10 +127,27 @@ | |
| 125 | ** longer than needed. |
| 126 | */ |
| 127 | void backoffice_no_delay(void){ |
| 128 | backofficeNoDelay = 1; |
| 129 | } |
| 130 | |
| 131 | /* |
| 132 | ** Parse a unsigned 64-bit integer from a string. Return a pointer |
| 133 | ** to the character of z[] that occurs after the integer. |
| 134 | */ |
| @@ -170,17 +189,35 @@ | |
| 170 | " VALUES('backoffice','%lld %lld %lld %lld',now())", |
| 171 | pLease->idCurrent, pLease->tmCurrent, |
| 172 | pLease->idNext, pLease->tmNext); |
| 173 | } |
| 174 | |
| 175 | /* |
| 176 | ** Check to see if the process identified by pid is alive. If |
| 177 | ** we cannot prove the the process is dead, return true. |
| 178 | */ |
| 179 | static int backofficeProcessExists(sqlite3_uint64 pid){ |
| 180 | #if defined(_WIN32) |
| 181 | return 1; |
| 182 | #else |
| 183 | return pid>0 && kill((pid_t)pid, 0)==0; |
| 184 | #endif |
| 185 | } |
| 186 | |
| @@ -188,39 +225,65 @@ | |
| 188 | ** Check to see if the process identified by pid has finished. If |
| 189 | ** we cannot prove the the process is still running, return true. |
| 190 | */ |
| 191 | static int backofficeProcessDone(sqlite3_uint64 pid){ |
| 192 | #if defined(_WIN32) |
| 193 | return 1; |
| 194 | #else |
| 195 | return pid<=0 || kill((pid_t)pid, 0)!=0; |
| 196 | #endif |
| 197 | } |
| 198 | |
| 199 | /* |
| 200 | ** Return a process id number for the current process |
| 201 | */ |
| 202 | static sqlite3_uint64 backofficeProcessId(void){ |
| 203 | #if defined(_WIN32) |
| 204 | return (sqlite3_uint64)GetCurrentProcessId(); |
| 205 | #else |
| 206 | return (sqlite3_uint64)getpid(); |
| 207 | #endif |
| 208 | } |
| 209 | |
| 210 | /* |
| 211 | ** Set an alarm to cause the process to exit after "x" seconds. This |
| 212 | ** prevents any kind of bug from keeping a backoffice process running |
| 213 | ** indefinitely. |
| 214 | */ |
| 215 | #if !defined(_WIN32) |
| 216 | static void backofficeSigalrmHandler(int x){ |
| 217 | fossil_panic("backoffice timeout"); |
| 218 | } |
| 219 | #endif |
| 220 | static void backofficeTimeout(int x){ |
| 221 | #if !defined(_WIN32) |
| 222 | signal(SIGALRM, backofficeSigalrmHandler); |
| 223 | alarm(x); |
| 224 | #endif |
| 225 | } |
| 226 | |
| @@ -334,11 +397,11 @@ | |
| 334 | x.tmNext = 0; |
| 335 | backofficeWriteLease(&x); |
| 336 | db_end_transaction(0); |
| 337 | if( g.fAnyTrace ){ |
| 338 | fprintf(stderr, "/***** Begin Backoffice Processing %d *****/\n", |
| 339 | getpid()); |
| 340 | } |
| 341 | backoffice_work(); |
| 342 | break; |
| 343 | } |
| 344 | if( backofficeNoDelay || db_get_boolean("backoffice-nodelay",1) ){ |
| @@ -353,25 +416,42 @@ | |
| 353 | x.idNext = idSelf; |
| 354 | x.tmNext = (tmNow>x.tmCurrent ? tmNow : x.tmCurrent) + BKOFCE_LEASE_TIME; |
| 355 | backofficeWriteLease(&x); |
| 356 | db_end_transaction(0); |
| 357 | if( g.fAnyTrace ){ |
| 358 | fprintf(stderr, "/***** Backoffice On-deck %d *****/\n", getpid()); |
| 359 | } |
| 360 | if( x.tmCurrent >= tmNow ){ |
| 361 | sqlite3_sleep(1000*(x.tmCurrent - tmNow + 1)); |
| 362 | }else{ |
| 363 | if( lastWarning+warningDelay < tmNow ){ |
| 364 | fossil_warning( |
| 365 | "backoffice process %lld still running after %d seconds", |
| 366 | x.idCurrent, (int)(BKOFCE_LEASE_TIME + tmNow - x.tmCurrent)); |
| 367 | lastWarning = tmNow; |
| 368 | warningDelay *= 2; |
| 369 | } |
| 370 | sqlite3_sleep(1000); |
| 371 | } |
| 372 | } |
| 373 | return; |
| 374 | } |
| 375 | |
| 376 | /* |
| 377 | ** This routine runs to do the backoffice processing. When adding new |
| 378 |
| --- src/backoffice.c | |
| +++ src/backoffice.c | |
| @@ -62,14 +62,16 @@ | |
| 62 | #include <time.h> |
| 63 | #if defined(_WIN32) |
| 64 | # include <windows.h> |
| 65 | # include <stdio.h> |
| 66 | # include <process.h> |
| 67 | # define GETPID (int)GetCurrentProcessId |
| 68 | #else |
| 69 | # include <unistd.h> |
| 70 | # include <sys/types.h> |
| 71 | # include <signal.h> |
| 72 | # define GETPID getpid |
| 73 | #endif |
| 74 | |
| 75 | /* |
| 76 | ** The BKOFCE_LEASE_TIME is the amount of time for which a single backoffice |
| 77 | ** processing run is valid. Each backoffice run monopolizes the lease for |
| @@ -125,10 +127,27 @@ | |
| 127 | ** longer than needed. |
| 128 | */ |
| 129 | void backoffice_no_delay(void){ |
| 130 | backofficeNoDelay = 1; |
| 131 | } |
| 132 | |
| 133 | /* |
| 134 | ** Sleeps for the specified number of milliseconds -OR- until interrupted |
| 135 | ** by another thread (if supported by the underlying platform). Non-zero |
| 136 | ** will be returned if the sleep was interrupted. |
| 137 | */ |
| 138 | static int backofficeSleep(int milliseconds){ |
| 139 | #if defined(_WIN32) |
| 140 | assert( milliseconds>=0 ); |
| 141 | if( SleepEx((DWORD)milliseconds, TRUE)==WAIT_IO_COMPLETION ){ |
| 142 | return 1; |
| 143 | } |
| 144 | #else |
| 145 | sqlite3_sleep(milliseconds); |
| 146 | #endif |
| 147 | return 0; |
| 148 | } |
| 149 | |
| 150 | /* |
| 151 | ** Parse a unsigned 64-bit integer from a string. Return a pointer |
| 152 | ** to the character of z[] that occurs after the integer. |
| 153 | */ |
| @@ -170,17 +189,35 @@ | |
| 189 | " VALUES('backoffice','%lld %lld %lld %lld',now())", |
| 190 | pLease->idCurrent, pLease->tmCurrent, |
| 191 | pLease->idNext, pLease->tmNext); |
| 192 | } |
| 193 | |
| 194 | /* |
| 195 | ** Check to see if the specified Win32 process is still alive. It |
| 196 | ** should be noted that even if this function returns non-zero, the |
| 197 | ** process may die before another operation on it can be completed. |
| 198 | */ |
| 199 | #if defined(_WIN32) |
| 200 | #ifndef PROCESS_QUERY_LIMITED_INFORMATION |
| 201 | # define PROCESS_QUERY_LIMITED_INFORMATION (0x1000) |
| 202 | #endif |
| 203 | static int backofficeWin32ProcessExists(DWORD dwProcessId){ |
| 204 | HANDLE hProcess; |
| 205 | hProcess = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION,FALSE,dwProcessId); |
| 206 | if( hProcess==NULL ) return 0; |
| 207 | CloseHandle(hProcess); |
| 208 | return 1; |
| 209 | } |
| 210 | #endif |
| 211 | |
| 212 | /* |
| 213 | ** Check to see if the process identified by pid is alive. If |
| 214 | ** we cannot prove the the process is dead, return true. |
| 215 | */ |
| 216 | static int backofficeProcessExists(sqlite3_uint64 pid){ |
| 217 | #if defined(_WIN32) |
| 218 | return pid>0 && backofficeWin32ProcessExists((DWORD)pid)!=0; |
| 219 | #else |
| 220 | return pid>0 && kill((pid_t)pid, 0)==0; |
| 221 | #endif |
| 222 | } |
| 223 | |
| @@ -188,39 +225,65 @@ | |
| 225 | ** Check to see if the process identified by pid has finished. If |
| 226 | ** we cannot prove the the process is still running, return true. |
| 227 | */ |
| 228 | static int backofficeProcessDone(sqlite3_uint64 pid){ |
| 229 | #if defined(_WIN32) |
| 230 | return pid<=0 || backofficeWin32ProcessExists((DWORD)pid)==0; |
| 231 | #else |
| 232 | return pid<=0 || kill((pid_t)pid, 0)!=0; |
| 233 | #endif |
| 234 | } |
| 235 | |
| 236 | /* |
| 237 | ** Return a process id number for the current process |
| 238 | */ |
| 239 | static sqlite3_uint64 backofficeProcessId(void){ |
| 240 | return (sqlite3_uint64)GETPID(); |
| 241 | } |
| 242 | |
| 243 | /* |
| 244 | ** Set an alarm to cause the process to exit after "x" seconds. This |
| 245 | ** prevents any kind of bug from keeping a backoffice process running |
| 246 | ** indefinitely. |
| 247 | */ |
| 248 | static void backofficeSigalrmHandler(int x){ |
| 249 | fossil_panic("backoffice timeout (%d seconds)", x); |
| 250 | } |
| 251 | #if defined(_WIN32) |
| 252 | static void *threadHandle = NULL; |
| 253 | static void __stdcall backofficeWin32NoopApcProc(ULONG_PTR pArg){} /* NO-OP */ |
| 254 | static void backofficeWin32ThreadCleanup(){ |
| 255 | if( threadHandle!=NULL ){ |
| 256 | /* Queue no-op asynchronous procedure call to the sleeping |
| 257 | * thread. This will cause it to wake up with a non-zero |
| 258 | * return value. */ |
| 259 | if( QueueUserAPC(backofficeWin32NoopApcProc, threadHandle, 0) ){ |
| 260 | /* Wait for the thread to wake up and then exit. */ |
| 261 | WaitForSingleObject(threadHandle, INFINITE); |
| 262 | } |
| 263 | CloseHandle(threadHandle); |
| 264 | threadHandle = NULL; |
| 265 | } |
| 266 | } |
| 267 | static unsigned __stdcall backofficeWin32SigalrmThreadProc( |
| 268 | void *pArg /* IN: Pointer to integer number of whole seconds. */ |
| 269 | ){ |
| 270 | int seconds = FOSSIL_PTR_TO_INT(pArg); |
| 271 | if( SleepEx((DWORD)seconds * 1000, TRUE)==0 ){ |
| 272 | backofficeSigalrmHandler(seconds); |
| 273 | } |
| 274 | _endthreadex(0); |
| 275 | return 0; /* NOT REACHED */ |
| 276 | } |
| 277 | #endif |
| 278 | static void backofficeTimeout(int x){ |
| 279 | #if defined(_WIN32) |
| 280 | backofficeWin32ThreadCleanup(); |
| 281 | threadHandle = (void*)_beginthreadex( |
| 282 | 0, 0, backofficeWin32SigalrmThreadProc, FOSSIL_INT_TO_PTR(x), 0, 0 |
| 283 | ); |
| 284 | #else |
| 285 | signal(SIGALRM, backofficeSigalrmHandler); |
| 286 | alarm(x); |
| 287 | #endif |
| 288 | } |
| 289 | |
| @@ -334,11 +397,11 @@ | |
| 397 | x.tmNext = 0; |
| 398 | backofficeWriteLease(&x); |
| 399 | db_end_transaction(0); |
| 400 | if( g.fAnyTrace ){ |
| 401 | fprintf(stderr, "/***** Begin Backoffice Processing %d *****/\n", |
| 402 | GETPID()); |
| 403 | } |
| 404 | backoffice_work(); |
| 405 | break; |
| 406 | } |
| 407 | if( backofficeNoDelay || db_get_boolean("backoffice-nodelay",1) ){ |
| @@ -353,25 +416,42 @@ | |
| 416 | x.idNext = idSelf; |
| 417 | x.tmNext = (tmNow>x.tmCurrent ? tmNow : x.tmCurrent) + BKOFCE_LEASE_TIME; |
| 418 | backofficeWriteLease(&x); |
| 419 | db_end_transaction(0); |
| 420 | if( g.fAnyTrace ){ |
| 421 | fprintf(stderr, "/***** Backoffice On-deck %d *****/\n", GETPID()); |
| 422 | } |
| 423 | if( x.tmCurrent >= tmNow ){ |
| 424 | if( backofficeSleep(1000*(x.tmCurrent - tmNow + 1)) ){ |
| 425 | /* The sleep was interrupted by a signal from another thread. */ |
| 426 | if( g.fAnyTrace ){ |
| 427 | fprintf(stderr, "/***** Backoffice Interrupt %d *****/\n", GETPID()); |
| 428 | } |
| 429 | db_end_transaction(0); |
| 430 | break; |
| 431 | } |
| 432 | }else{ |
| 433 | if( lastWarning+warningDelay < tmNow ){ |
| 434 | fossil_warning( |
| 435 | "backoffice process %lld still running after %d seconds", |
| 436 | x.idCurrent, (int)(BKOFCE_LEASE_TIME + tmNow - x.tmCurrent)); |
| 437 | lastWarning = tmNow; |
| 438 | warningDelay *= 2; |
| 439 | } |
| 440 | if( backofficeSleep(1000) ){ |
| 441 | /* The sleep was interrupted by a signal from another thread. */ |
| 442 | if( g.fAnyTrace ){ |
| 443 | fprintf(stderr, "/***** Backoffice Interrupt %d *****/\n", GETPID()); |
| 444 | } |
| 445 | db_end_transaction(0); |
| 446 | break; |
| 447 | } |
| 448 | } |
| 449 | } |
| 450 | #if defined(_WIN32) |
| 451 | backofficeWin32ThreadCleanup(); |
| 452 | #endif |
| 453 | return; |
| 454 | } |
| 455 | |
| 456 | /* |
| 457 | ** This routine runs to do the backoffice processing. When adding new |
| 458 |
+94
-14
| --- src/backoffice.c | ||
| +++ src/backoffice.c | ||
| @@ -62,14 +62,16 @@ | ||
| 62 | 62 | #include <time.h> |
| 63 | 63 | #if defined(_WIN32) |
| 64 | 64 | # include <windows.h> |
| 65 | 65 | # include <stdio.h> |
| 66 | 66 | # include <process.h> |
| 67 | +# define GETPID (int)GetCurrentProcessId | |
| 67 | 68 | #else |
| 68 | 69 | # include <unistd.h> |
| 69 | 70 | # include <sys/types.h> |
| 70 | 71 | # include <signal.h> |
| 72 | +# define GETPID getpid | |
| 71 | 73 | #endif |
| 72 | 74 | |
| 73 | 75 | /* |
| 74 | 76 | ** The BKOFCE_LEASE_TIME is the amount of time for which a single backoffice |
| 75 | 77 | ** processing run is valid. Each backoffice run monopolizes the lease for |
| @@ -125,10 +127,27 @@ | ||
| 125 | 127 | ** longer than needed. |
| 126 | 128 | */ |
| 127 | 129 | void backoffice_no_delay(void){ |
| 128 | 130 | backofficeNoDelay = 1; |
| 129 | 131 | } |
| 132 | + | |
| 133 | +/* | |
| 134 | +** Sleeps for the specified number of milliseconds -OR- until interrupted | |
| 135 | +** by another thread (if supported by the underlying platform). Non-zero | |
| 136 | +** will be returned if the sleep was interrupted. | |
| 137 | +*/ | |
| 138 | +static int backofficeSleep(int milliseconds){ | |
| 139 | +#if defined(_WIN32) | |
| 140 | + assert( milliseconds>=0 ); | |
| 141 | + if( SleepEx((DWORD)milliseconds, TRUE)==WAIT_IO_COMPLETION ){ | |
| 142 | + return 1; | |
| 143 | + } | |
| 144 | +#else | |
| 145 | + sqlite3_sleep(milliseconds); | |
| 146 | +#endif | |
| 147 | + return 0; | |
| 148 | +} | |
| 130 | 149 | |
| 131 | 150 | /* |
| 132 | 151 | ** Parse a unsigned 64-bit integer from a string. Return a pointer |
| 133 | 152 | ** to the character of z[] that occurs after the integer. |
| 134 | 153 | */ |
| @@ -170,17 +189,35 @@ | ||
| 170 | 189 | " VALUES('backoffice','%lld %lld %lld %lld',now())", |
| 171 | 190 | pLease->idCurrent, pLease->tmCurrent, |
| 172 | 191 | pLease->idNext, pLease->tmNext); |
| 173 | 192 | } |
| 174 | 193 | |
| 194 | +/* | |
| 195 | +** Check to see if the specified Win32 process is still alive. It | |
| 196 | +** should be noted that even if this function returns non-zero, the | |
| 197 | +** process may die before another operation on it can be completed. | |
| 198 | +*/ | |
| 199 | +#if defined(_WIN32) | |
| 200 | +#ifndef PROCESS_QUERY_LIMITED_INFORMATION | |
| 201 | +# define PROCESS_QUERY_LIMITED_INFORMATION (0x1000) | |
| 202 | +#endif | |
| 203 | +static int backofficeWin32ProcessExists(DWORD dwProcessId){ | |
| 204 | + HANDLE hProcess; | |
| 205 | + hProcess = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION,FALSE,dwProcessId); | |
| 206 | + if( hProcess==NULL ) return 0; | |
| 207 | + CloseHandle(hProcess); | |
| 208 | + return 1; | |
| 209 | +} | |
| 210 | +#endif | |
| 211 | + | |
| 175 | 212 | /* |
| 176 | 213 | ** Check to see if the process identified by pid is alive. If |
| 177 | 214 | ** we cannot prove the the process is dead, return true. |
| 178 | 215 | */ |
| 179 | 216 | static int backofficeProcessExists(sqlite3_uint64 pid){ |
| 180 | 217 | #if defined(_WIN32) |
| 181 | - return 1; | |
| 218 | + return pid>0 && backofficeWin32ProcessExists((DWORD)pid)!=0; | |
| 182 | 219 | #else |
| 183 | 220 | return pid>0 && kill((pid_t)pid, 0)==0; |
| 184 | 221 | #endif |
| 185 | 222 | } |
| 186 | 223 | |
| @@ -188,39 +225,65 @@ | ||
| 188 | 225 | ** Check to see if the process identified by pid has finished. If |
| 189 | 226 | ** we cannot prove the the process is still running, return true. |
| 190 | 227 | */ |
| 191 | 228 | static int backofficeProcessDone(sqlite3_uint64 pid){ |
| 192 | 229 | #if defined(_WIN32) |
| 193 | - return 1; | |
| 230 | + return pid<=0 || backofficeWin32ProcessExists((DWORD)pid)==0; | |
| 194 | 231 | #else |
| 195 | 232 | return pid<=0 || kill((pid_t)pid, 0)!=0; |
| 196 | 233 | #endif |
| 197 | 234 | } |
| 198 | 235 | |
| 199 | 236 | /* |
| 200 | 237 | ** Return a process id number for the current process |
| 201 | 238 | */ |
| 202 | 239 | static sqlite3_uint64 backofficeProcessId(void){ |
| 203 | -#if defined(_WIN32) | |
| 204 | - return (sqlite3_uint64)GetCurrentProcessId(); | |
| 205 | -#else | |
| 206 | - return (sqlite3_uint64)getpid(); | |
| 207 | -#endif | |
| 240 | + return (sqlite3_uint64)GETPID(); | |
| 208 | 241 | } |
| 209 | 242 | |
| 210 | 243 | /* |
| 211 | 244 | ** Set an alarm to cause the process to exit after "x" seconds. This |
| 212 | 245 | ** prevents any kind of bug from keeping a backoffice process running |
| 213 | 246 | ** indefinitely. |
| 214 | 247 | */ |
| 215 | -#if !defined(_WIN32) | |
| 216 | 248 | static void backofficeSigalrmHandler(int x){ |
| 217 | - fossil_panic("backoffice timeout"); | |
| 249 | + fossil_panic("backoffice timeout (%d seconds)", x); | |
| 250 | +} | |
| 251 | +#if defined(_WIN32) | |
| 252 | +static void *threadHandle = NULL; | |
| 253 | +static void __stdcall backofficeWin32NoopApcProc(ULONG_PTR pArg){} /* NO-OP */ | |
| 254 | +static void backofficeWin32ThreadCleanup(){ | |
| 255 | + if( threadHandle!=NULL ){ | |
| 256 | + /* Queue no-op asynchronous procedure call to the sleeping | |
| 257 | + * thread. This will cause it to wake up with a non-zero | |
| 258 | + * return value. */ | |
| 259 | + if( QueueUserAPC(backofficeWin32NoopApcProc, threadHandle, 0) ){ | |
| 260 | + /* Wait for the thread to wake up and then exit. */ | |
| 261 | + WaitForSingleObject(threadHandle, INFINITE); | |
| 262 | + } | |
| 263 | + CloseHandle(threadHandle); | |
| 264 | + threadHandle = NULL; | |
| 265 | + } | |
| 266 | +} | |
| 267 | +static unsigned __stdcall backofficeWin32SigalrmThreadProc( | |
| 268 | + void *pArg /* IN: Pointer to integer number of whole seconds. */ | |
| 269 | +){ | |
| 270 | + int seconds = FOSSIL_PTR_TO_INT(pArg); | |
| 271 | + if( SleepEx((DWORD)seconds * 1000, TRUE)==0 ){ | |
| 272 | + backofficeSigalrmHandler(seconds); | |
| 273 | + } | |
| 274 | + _endthreadex(0); | |
| 275 | + return 0; /* NOT REACHED */ | |
| 218 | 276 | } |
| 219 | 277 | #endif |
| 220 | 278 | static void backofficeTimeout(int x){ |
| 221 | -#if !defined(_WIN32) | |
| 279 | +#if defined(_WIN32) | |
| 280 | + backofficeWin32ThreadCleanup(); | |
| 281 | + threadHandle = (void*)_beginthreadex( | |
| 282 | + 0, 0, backofficeWin32SigalrmThreadProc, FOSSIL_INT_TO_PTR(x), 0, 0 | |
| 283 | + ); | |
| 284 | +#else | |
| 222 | 285 | signal(SIGALRM, backofficeSigalrmHandler); |
| 223 | 286 | alarm(x); |
| 224 | 287 | #endif |
| 225 | 288 | } |
| 226 | 289 | |
| @@ -334,11 +397,11 @@ | ||
| 334 | 397 | x.tmNext = 0; |
| 335 | 398 | backofficeWriteLease(&x); |
| 336 | 399 | db_end_transaction(0); |
| 337 | 400 | if( g.fAnyTrace ){ |
| 338 | 401 | fprintf(stderr, "/***** Begin Backoffice Processing %d *****/\n", |
| 339 | - getpid()); | |
| 402 | + GETPID()); | |
| 340 | 403 | } |
| 341 | 404 | backoffice_work(); |
| 342 | 405 | break; |
| 343 | 406 | } |
| 344 | 407 | if( backofficeNoDelay || db_get_boolean("backoffice-nodelay",1) ){ |
| @@ -353,25 +416,42 @@ | ||
| 353 | 416 | x.idNext = idSelf; |
| 354 | 417 | x.tmNext = (tmNow>x.tmCurrent ? tmNow : x.tmCurrent) + BKOFCE_LEASE_TIME; |
| 355 | 418 | backofficeWriteLease(&x); |
| 356 | 419 | db_end_transaction(0); |
| 357 | 420 | if( g.fAnyTrace ){ |
| 358 | - fprintf(stderr, "/***** Backoffice On-deck %d *****/\n", getpid()); | |
| 421 | + fprintf(stderr, "/***** Backoffice On-deck %d *****/\n", GETPID()); | |
| 359 | 422 | } |
| 360 | 423 | if( x.tmCurrent >= tmNow ){ |
| 361 | - sqlite3_sleep(1000*(x.tmCurrent - tmNow + 1)); | |
| 424 | + if( backofficeSleep(1000*(x.tmCurrent - tmNow + 1)) ){ | |
| 425 | + /* The sleep was interrupted by a signal from another thread. */ | |
| 426 | + if( g.fAnyTrace ){ | |
| 427 | + fprintf(stderr, "/***** Backoffice Interrupt %d *****/\n", GETPID()); | |
| 428 | + } | |
| 429 | + db_end_transaction(0); | |
| 430 | + break; | |
| 431 | + } | |
| 362 | 432 | }else{ |
| 363 | 433 | if( lastWarning+warningDelay < tmNow ){ |
| 364 | 434 | fossil_warning( |
| 365 | 435 | "backoffice process %lld still running after %d seconds", |
| 366 | 436 | x.idCurrent, (int)(BKOFCE_LEASE_TIME + tmNow - x.tmCurrent)); |
| 367 | 437 | lastWarning = tmNow; |
| 368 | 438 | warningDelay *= 2; |
| 369 | 439 | } |
| 370 | - sqlite3_sleep(1000); | |
| 440 | + if( backofficeSleep(1000) ){ | |
| 441 | + /* The sleep was interrupted by a signal from another thread. */ | |
| 442 | + if( g.fAnyTrace ){ | |
| 443 | + fprintf(stderr, "/***** Backoffice Interrupt %d *****/\n", GETPID()); | |
| 444 | + } | |
| 445 | + db_end_transaction(0); | |
| 446 | + break; | |
| 447 | + } | |
| 371 | 448 | } |
| 372 | 449 | } |
| 450 | +#if defined(_WIN32) | |
| 451 | + backofficeWin32ThreadCleanup(); | |
| 452 | +#endif | |
| 373 | 453 | return; |
| 374 | 454 | } |
| 375 | 455 | |
| 376 | 456 | /* |
| 377 | 457 | ** This routine runs to do the backoffice processing. When adding new |
| 378 | 458 |
| --- src/backoffice.c | |
| +++ src/backoffice.c | |
| @@ -62,14 +62,16 @@ | |
| 62 | #include <time.h> |
| 63 | #if defined(_WIN32) |
| 64 | # include <windows.h> |
| 65 | # include <stdio.h> |
| 66 | # include <process.h> |
| 67 | #else |
| 68 | # include <unistd.h> |
| 69 | # include <sys/types.h> |
| 70 | # include <signal.h> |
| 71 | #endif |
| 72 | |
| 73 | /* |
| 74 | ** The BKOFCE_LEASE_TIME is the amount of time for which a single backoffice |
| 75 | ** processing run is valid. Each backoffice run monopolizes the lease for |
| @@ -125,10 +127,27 @@ | |
| 125 | ** longer than needed. |
| 126 | */ |
| 127 | void backoffice_no_delay(void){ |
| 128 | backofficeNoDelay = 1; |
| 129 | } |
| 130 | |
| 131 | /* |
| 132 | ** Parse a unsigned 64-bit integer from a string. Return a pointer |
| 133 | ** to the character of z[] that occurs after the integer. |
| 134 | */ |
| @@ -170,17 +189,35 @@ | |
| 170 | " VALUES('backoffice','%lld %lld %lld %lld',now())", |
| 171 | pLease->idCurrent, pLease->tmCurrent, |
| 172 | pLease->idNext, pLease->tmNext); |
| 173 | } |
| 174 | |
| 175 | /* |
| 176 | ** Check to see if the process identified by pid is alive. If |
| 177 | ** we cannot prove the the process is dead, return true. |
| 178 | */ |
| 179 | static int backofficeProcessExists(sqlite3_uint64 pid){ |
| 180 | #if defined(_WIN32) |
| 181 | return 1; |
| 182 | #else |
| 183 | return pid>0 && kill((pid_t)pid, 0)==0; |
| 184 | #endif |
| 185 | } |
| 186 | |
| @@ -188,39 +225,65 @@ | |
| 188 | ** Check to see if the process identified by pid has finished. If |
| 189 | ** we cannot prove the the process is still running, return true. |
| 190 | */ |
| 191 | static int backofficeProcessDone(sqlite3_uint64 pid){ |
| 192 | #if defined(_WIN32) |
| 193 | return 1; |
| 194 | #else |
| 195 | return pid<=0 || kill((pid_t)pid, 0)!=0; |
| 196 | #endif |
| 197 | } |
| 198 | |
| 199 | /* |
| 200 | ** Return a process id number for the current process |
| 201 | */ |
| 202 | static sqlite3_uint64 backofficeProcessId(void){ |
| 203 | #if defined(_WIN32) |
| 204 | return (sqlite3_uint64)GetCurrentProcessId(); |
| 205 | #else |
| 206 | return (sqlite3_uint64)getpid(); |
| 207 | #endif |
| 208 | } |
| 209 | |
| 210 | /* |
| 211 | ** Set an alarm to cause the process to exit after "x" seconds. This |
| 212 | ** prevents any kind of bug from keeping a backoffice process running |
| 213 | ** indefinitely. |
| 214 | */ |
| 215 | #if !defined(_WIN32) |
| 216 | static void backofficeSigalrmHandler(int x){ |
| 217 | fossil_panic("backoffice timeout"); |
| 218 | } |
| 219 | #endif |
| 220 | static void backofficeTimeout(int x){ |
| 221 | #if !defined(_WIN32) |
| 222 | signal(SIGALRM, backofficeSigalrmHandler); |
| 223 | alarm(x); |
| 224 | #endif |
| 225 | } |
| 226 | |
| @@ -334,11 +397,11 @@ | |
| 334 | x.tmNext = 0; |
| 335 | backofficeWriteLease(&x); |
| 336 | db_end_transaction(0); |
| 337 | if( g.fAnyTrace ){ |
| 338 | fprintf(stderr, "/***** Begin Backoffice Processing %d *****/\n", |
| 339 | getpid()); |
| 340 | } |
| 341 | backoffice_work(); |
| 342 | break; |
| 343 | } |
| 344 | if( backofficeNoDelay || db_get_boolean("backoffice-nodelay",1) ){ |
| @@ -353,25 +416,42 @@ | |
| 353 | x.idNext = idSelf; |
| 354 | x.tmNext = (tmNow>x.tmCurrent ? tmNow : x.tmCurrent) + BKOFCE_LEASE_TIME; |
| 355 | backofficeWriteLease(&x); |
| 356 | db_end_transaction(0); |
| 357 | if( g.fAnyTrace ){ |
| 358 | fprintf(stderr, "/***** Backoffice On-deck %d *****/\n", getpid()); |
| 359 | } |
| 360 | if( x.tmCurrent >= tmNow ){ |
| 361 | sqlite3_sleep(1000*(x.tmCurrent - tmNow + 1)); |
| 362 | }else{ |
| 363 | if( lastWarning+warningDelay < tmNow ){ |
| 364 | fossil_warning( |
| 365 | "backoffice process %lld still running after %d seconds", |
| 366 | x.idCurrent, (int)(BKOFCE_LEASE_TIME + tmNow - x.tmCurrent)); |
| 367 | lastWarning = tmNow; |
| 368 | warningDelay *= 2; |
| 369 | } |
| 370 | sqlite3_sleep(1000); |
| 371 | } |
| 372 | } |
| 373 | return; |
| 374 | } |
| 375 | |
| 376 | /* |
| 377 | ** This routine runs to do the backoffice processing. When adding new |
| 378 |
| --- src/backoffice.c | |
| +++ src/backoffice.c | |
| @@ -62,14 +62,16 @@ | |
| 62 | #include <time.h> |
| 63 | #if defined(_WIN32) |
| 64 | # include <windows.h> |
| 65 | # include <stdio.h> |
| 66 | # include <process.h> |
| 67 | # define GETPID (int)GetCurrentProcessId |
| 68 | #else |
| 69 | # include <unistd.h> |
| 70 | # include <sys/types.h> |
| 71 | # include <signal.h> |
| 72 | # define GETPID getpid |
| 73 | #endif |
| 74 | |
| 75 | /* |
| 76 | ** The BKOFCE_LEASE_TIME is the amount of time for which a single backoffice |
| 77 | ** processing run is valid. Each backoffice run monopolizes the lease for |
| @@ -125,10 +127,27 @@ | |
| 127 | ** longer than needed. |
| 128 | */ |
| 129 | void backoffice_no_delay(void){ |
| 130 | backofficeNoDelay = 1; |
| 131 | } |
| 132 | |
| 133 | /* |
| 134 | ** Sleeps for the specified number of milliseconds -OR- until interrupted |
| 135 | ** by another thread (if supported by the underlying platform). Non-zero |
| 136 | ** will be returned if the sleep was interrupted. |
| 137 | */ |
| 138 | static int backofficeSleep(int milliseconds){ |
| 139 | #if defined(_WIN32) |
| 140 | assert( milliseconds>=0 ); |
| 141 | if( SleepEx((DWORD)milliseconds, TRUE)==WAIT_IO_COMPLETION ){ |
| 142 | return 1; |
| 143 | } |
| 144 | #else |
| 145 | sqlite3_sleep(milliseconds); |
| 146 | #endif |
| 147 | return 0; |
| 148 | } |
| 149 | |
| 150 | /* |
| 151 | ** Parse a unsigned 64-bit integer from a string. Return a pointer |
| 152 | ** to the character of z[] that occurs after the integer. |
| 153 | */ |
| @@ -170,17 +189,35 @@ | |
| 189 | " VALUES('backoffice','%lld %lld %lld %lld',now())", |
| 190 | pLease->idCurrent, pLease->tmCurrent, |
| 191 | pLease->idNext, pLease->tmNext); |
| 192 | } |
| 193 | |
| 194 | /* |
| 195 | ** Check to see if the specified Win32 process is still alive. It |
| 196 | ** should be noted that even if this function returns non-zero, the |
| 197 | ** process may die before another operation on it can be completed. |
| 198 | */ |
| 199 | #if defined(_WIN32) |
| 200 | #ifndef PROCESS_QUERY_LIMITED_INFORMATION |
| 201 | # define PROCESS_QUERY_LIMITED_INFORMATION (0x1000) |
| 202 | #endif |
| 203 | static int backofficeWin32ProcessExists(DWORD dwProcessId){ |
| 204 | HANDLE hProcess; |
| 205 | hProcess = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION,FALSE,dwProcessId); |
| 206 | if( hProcess==NULL ) return 0; |
| 207 | CloseHandle(hProcess); |
| 208 | return 1; |
| 209 | } |
| 210 | #endif |
| 211 | |
| 212 | /* |
| 213 | ** Check to see if the process identified by pid is alive. If |
| 214 | ** we cannot prove the the process is dead, return true. |
| 215 | */ |
| 216 | static int backofficeProcessExists(sqlite3_uint64 pid){ |
| 217 | #if defined(_WIN32) |
| 218 | return pid>0 && backofficeWin32ProcessExists((DWORD)pid)!=0; |
| 219 | #else |
| 220 | return pid>0 && kill((pid_t)pid, 0)==0; |
| 221 | #endif |
| 222 | } |
| 223 | |
| @@ -188,39 +225,65 @@ | |
| 225 | ** Check to see if the process identified by pid has finished. If |
| 226 | ** we cannot prove the the process is still running, return true. |
| 227 | */ |
| 228 | static int backofficeProcessDone(sqlite3_uint64 pid){ |
| 229 | #if defined(_WIN32) |
| 230 | return pid<=0 || backofficeWin32ProcessExists((DWORD)pid)==0; |
| 231 | #else |
| 232 | return pid<=0 || kill((pid_t)pid, 0)!=0; |
| 233 | #endif |
| 234 | } |
| 235 | |
| 236 | /* |
| 237 | ** Return a process id number for the current process |
| 238 | */ |
| 239 | static sqlite3_uint64 backofficeProcessId(void){ |
| 240 | return (sqlite3_uint64)GETPID(); |
| 241 | } |
| 242 | |
| 243 | /* |
| 244 | ** Set an alarm to cause the process to exit after "x" seconds. This |
| 245 | ** prevents any kind of bug from keeping a backoffice process running |
| 246 | ** indefinitely. |
| 247 | */ |
| 248 | static void backofficeSigalrmHandler(int x){ |
| 249 | fossil_panic("backoffice timeout (%d seconds)", x); |
| 250 | } |
| 251 | #if defined(_WIN32) |
| 252 | static void *threadHandle = NULL; |
| 253 | static void __stdcall backofficeWin32NoopApcProc(ULONG_PTR pArg){} /* NO-OP */ |
| 254 | static void backofficeWin32ThreadCleanup(){ |
| 255 | if( threadHandle!=NULL ){ |
| 256 | /* Queue no-op asynchronous procedure call to the sleeping |
| 257 | * thread. This will cause it to wake up with a non-zero |
| 258 | * return value. */ |
| 259 | if( QueueUserAPC(backofficeWin32NoopApcProc, threadHandle, 0) ){ |
| 260 | /* Wait for the thread to wake up and then exit. */ |
| 261 | WaitForSingleObject(threadHandle, INFINITE); |
| 262 | } |
| 263 | CloseHandle(threadHandle); |
| 264 | threadHandle = NULL; |
| 265 | } |
| 266 | } |
| 267 | static unsigned __stdcall backofficeWin32SigalrmThreadProc( |
| 268 | void *pArg /* IN: Pointer to integer number of whole seconds. */ |
| 269 | ){ |
| 270 | int seconds = FOSSIL_PTR_TO_INT(pArg); |
| 271 | if( SleepEx((DWORD)seconds * 1000, TRUE)==0 ){ |
| 272 | backofficeSigalrmHandler(seconds); |
| 273 | } |
| 274 | _endthreadex(0); |
| 275 | return 0; /* NOT REACHED */ |
| 276 | } |
| 277 | #endif |
| 278 | static void backofficeTimeout(int x){ |
| 279 | #if defined(_WIN32) |
| 280 | backofficeWin32ThreadCleanup(); |
| 281 | threadHandle = (void*)_beginthreadex( |
| 282 | 0, 0, backofficeWin32SigalrmThreadProc, FOSSIL_INT_TO_PTR(x), 0, 0 |
| 283 | ); |
| 284 | #else |
| 285 | signal(SIGALRM, backofficeSigalrmHandler); |
| 286 | alarm(x); |
| 287 | #endif |
| 288 | } |
| 289 | |
| @@ -334,11 +397,11 @@ | |
| 397 | x.tmNext = 0; |
| 398 | backofficeWriteLease(&x); |
| 399 | db_end_transaction(0); |
| 400 | if( g.fAnyTrace ){ |
| 401 | fprintf(stderr, "/***** Begin Backoffice Processing %d *****/\n", |
| 402 | GETPID()); |
| 403 | } |
| 404 | backoffice_work(); |
| 405 | break; |
| 406 | } |
| 407 | if( backofficeNoDelay || db_get_boolean("backoffice-nodelay",1) ){ |
| @@ -353,25 +416,42 @@ | |
| 416 | x.idNext = idSelf; |
| 417 | x.tmNext = (tmNow>x.tmCurrent ? tmNow : x.tmCurrent) + BKOFCE_LEASE_TIME; |
| 418 | backofficeWriteLease(&x); |
| 419 | db_end_transaction(0); |
| 420 | if( g.fAnyTrace ){ |
| 421 | fprintf(stderr, "/***** Backoffice On-deck %d *****/\n", GETPID()); |
| 422 | } |
| 423 | if( x.tmCurrent >= tmNow ){ |
| 424 | if( backofficeSleep(1000*(x.tmCurrent - tmNow + 1)) ){ |
| 425 | /* The sleep was interrupted by a signal from another thread. */ |
| 426 | if( g.fAnyTrace ){ |
| 427 | fprintf(stderr, "/***** Backoffice Interrupt %d *****/\n", GETPID()); |
| 428 | } |
| 429 | db_end_transaction(0); |
| 430 | break; |
| 431 | } |
| 432 | }else{ |
| 433 | if( lastWarning+warningDelay < tmNow ){ |
| 434 | fossil_warning( |
| 435 | "backoffice process %lld still running after %d seconds", |
| 436 | x.idCurrent, (int)(BKOFCE_LEASE_TIME + tmNow - x.tmCurrent)); |
| 437 | lastWarning = tmNow; |
| 438 | warningDelay *= 2; |
| 439 | } |
| 440 | if( backofficeSleep(1000) ){ |
| 441 | /* The sleep was interrupted by a signal from another thread. */ |
| 442 | if( g.fAnyTrace ){ |
| 443 | fprintf(stderr, "/***** Backoffice Interrupt %d *****/\n", GETPID()); |
| 444 | } |
| 445 | db_end_transaction(0); |
| 446 | break; |
| 447 | } |
| 448 | } |
| 449 | } |
| 450 | #if defined(_WIN32) |
| 451 | backofficeWin32ThreadCleanup(); |
| 452 | #endif |
| 453 | return; |
| 454 | } |
| 455 | |
| 456 | /* |
| 457 | ** This routine runs to do the backoffice processing. When adding new |
| 458 |