Fossil SCM

Improved windows code for the backoffice. Properly check to see if processes still exist. Provide a timeout feature.

drh 2018-08-07 20:58 trunk merge
Commit 43c29877be3939b16a5abcf5be925a15c7b44382f8752bcc2b11f23d6ba62ef8
2 files changed +94 -14 +94 -14
+94 -14
--- src/backoffice.c
+++ src/backoffice.c
@@ -62,14 +62,16 @@
6262
#include <time.h>
6363
#if defined(_WIN32)
6464
# include <windows.h>
6565
# include <stdio.h>
6666
# include <process.h>
67
+# define GETPID (int)GetCurrentProcessId
6768
#else
6869
# include <unistd.h>
6970
# include <sys/types.h>
7071
# include <signal.h>
72
+# define GETPID getpid
7173
#endif
7274
7375
/*
7476
** The BKOFCE_LEASE_TIME is the amount of time for which a single backoffice
7577
** processing run is valid. Each backoffice run monopolizes the lease for
@@ -125,10 +127,27 @@
125127
** longer than needed.
126128
*/
127129
void backoffice_no_delay(void){
128130
backofficeNoDelay = 1;
129131
}
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
+}
130149
131150
/*
132151
** Parse a unsigned 64-bit integer from a string. Return a pointer
133152
** to the character of z[] that occurs after the integer.
134153
*/
@@ -170,17 +189,35 @@
170189
" VALUES('backoffice','%lld %lld %lld %lld',now())",
171190
pLease->idCurrent, pLease->tmCurrent,
172191
pLease->idNext, pLease->tmNext);
173192
}
174193
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
+
175212
/*
176213
** Check to see if the process identified by pid is alive. If
177214
** we cannot prove the the process is dead, return true.
178215
*/
179216
static int backofficeProcessExists(sqlite3_uint64 pid){
180217
#if defined(_WIN32)
181
- return 1;
218
+ return pid>0 && backofficeWin32ProcessExists((DWORD)pid)!=0;
182219
#else
183220
return pid>0 && kill((pid_t)pid, 0)==0;
184221
#endif
185222
}
186223
@@ -188,39 +225,65 @@
188225
** Check to see if the process identified by pid has finished. If
189226
** we cannot prove the the process is still running, return true.
190227
*/
191228
static int backofficeProcessDone(sqlite3_uint64 pid){
192229
#if defined(_WIN32)
193
- return 1;
230
+ return pid<=0 || backofficeWin32ProcessExists((DWORD)pid)==0;
194231
#else
195232
return pid<=0 || kill((pid_t)pid, 0)!=0;
196233
#endif
197234
}
198235
199236
/*
200237
** Return a process id number for the current process
201238
*/
202239
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();
208241
}
209242
210243
/*
211244
** Set an alarm to cause the process to exit after "x" seconds. This
212245
** prevents any kind of bug from keeping a backoffice process running
213246
** indefinitely.
214247
*/
215
-#if !defined(_WIN32)
216248
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 */
218276
}
219277
#endif
220278
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
222285
signal(SIGALRM, backofficeSigalrmHandler);
223286
alarm(x);
224287
#endif
225288
}
226289
@@ -334,11 +397,11 @@
334397
x.tmNext = 0;
335398
backofficeWriteLease(&x);
336399
db_end_transaction(0);
337400
if( g.fAnyTrace ){
338401
fprintf(stderr, "/***** Begin Backoffice Processing %d *****/\n",
339
- getpid());
402
+ GETPID());
340403
}
341404
backoffice_work();
342405
break;
343406
}
344407
if( backofficeNoDelay || db_get_boolean("backoffice-nodelay",1) ){
@@ -353,25 +416,42 @@
353416
x.idNext = idSelf;
354417
x.tmNext = (tmNow>x.tmCurrent ? tmNow : x.tmCurrent) + BKOFCE_LEASE_TIME;
355418
backofficeWriteLease(&x);
356419
db_end_transaction(0);
357420
if( g.fAnyTrace ){
358
- fprintf(stderr, "/***** Backoffice On-deck %d *****/\n", getpid());
421
+ fprintf(stderr, "/***** Backoffice On-deck %d *****/\n", GETPID());
359422
}
360423
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
+ }
362432
}else{
363433
if( lastWarning+warningDelay < tmNow ){
364434
fossil_warning(
365435
"backoffice process %lld still running after %d seconds",
366436
x.idCurrent, (int)(BKOFCE_LEASE_TIME + tmNow - x.tmCurrent));
367437
lastWarning = tmNow;
368438
warningDelay *= 2;
369439
}
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
+ }
371448
}
372449
}
450
+#if defined(_WIN32)
451
+ backofficeWin32ThreadCleanup();
452
+#endif
373453
return;
374454
}
375455
376456
/*
377457
** This routine runs to do the backoffice processing. When adding new
378458
--- 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 @@
6262
#include <time.h>
6363
#if defined(_WIN32)
6464
# include <windows.h>
6565
# include <stdio.h>
6666
# include <process.h>
67
+# define GETPID (int)GetCurrentProcessId
6768
#else
6869
# include <unistd.h>
6970
# include <sys/types.h>
7071
# include <signal.h>
72
+# define GETPID getpid
7173
#endif
7274
7375
/*
7476
** The BKOFCE_LEASE_TIME is the amount of time for which a single backoffice
7577
** processing run is valid. Each backoffice run monopolizes the lease for
@@ -125,10 +127,27 @@
125127
** longer than needed.
126128
*/
127129
void backoffice_no_delay(void){
128130
backofficeNoDelay = 1;
129131
}
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
+}
130149
131150
/*
132151
** Parse a unsigned 64-bit integer from a string. Return a pointer
133152
** to the character of z[] that occurs after the integer.
134153
*/
@@ -170,17 +189,35 @@
170189
" VALUES('backoffice','%lld %lld %lld %lld',now())",
171190
pLease->idCurrent, pLease->tmCurrent,
172191
pLease->idNext, pLease->tmNext);
173192
}
174193
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
+
175212
/*
176213
** Check to see if the process identified by pid is alive. If
177214
** we cannot prove the the process is dead, return true.
178215
*/
179216
static int backofficeProcessExists(sqlite3_uint64 pid){
180217
#if defined(_WIN32)
181
- return 1;
218
+ return pid>0 && backofficeWin32ProcessExists((DWORD)pid)!=0;
182219
#else
183220
return pid>0 && kill((pid_t)pid, 0)==0;
184221
#endif
185222
}
186223
@@ -188,39 +225,65 @@
188225
** Check to see if the process identified by pid has finished. If
189226
** we cannot prove the the process is still running, return true.
190227
*/
191228
static int backofficeProcessDone(sqlite3_uint64 pid){
192229
#if defined(_WIN32)
193
- return 1;
230
+ return pid<=0 || backofficeWin32ProcessExists((DWORD)pid)==0;
194231
#else
195232
return pid<=0 || kill((pid_t)pid, 0)!=0;
196233
#endif
197234
}
198235
199236
/*
200237
** Return a process id number for the current process
201238
*/
202239
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();
208241
}
209242
210243
/*
211244
** Set an alarm to cause the process to exit after "x" seconds. This
212245
** prevents any kind of bug from keeping a backoffice process running
213246
** indefinitely.
214247
*/
215
-#if !defined(_WIN32)
216248
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 */
218276
}
219277
#endif
220278
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
222285
signal(SIGALRM, backofficeSigalrmHandler);
223286
alarm(x);
224287
#endif
225288
}
226289
@@ -334,11 +397,11 @@
334397
x.tmNext = 0;
335398
backofficeWriteLease(&x);
336399
db_end_transaction(0);
337400
if( g.fAnyTrace ){
338401
fprintf(stderr, "/***** Begin Backoffice Processing %d *****/\n",
339
- getpid());
402
+ GETPID());
340403
}
341404
backoffice_work();
342405
break;
343406
}
344407
if( backofficeNoDelay || db_get_boolean("backoffice-nodelay",1) ){
@@ -353,25 +416,42 @@
353416
x.idNext = idSelf;
354417
x.tmNext = (tmNow>x.tmCurrent ? tmNow : x.tmCurrent) + BKOFCE_LEASE_TIME;
355418
backofficeWriteLease(&x);
356419
db_end_transaction(0);
357420
if( g.fAnyTrace ){
358
- fprintf(stderr, "/***** Backoffice On-deck %d *****/\n", getpid());
421
+ fprintf(stderr, "/***** Backoffice On-deck %d *****/\n", GETPID());
359422
}
360423
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
+ }
362432
}else{
363433
if( lastWarning+warningDelay < tmNow ){
364434
fossil_warning(
365435
"backoffice process %lld still running after %d seconds",
366436
x.idCurrent, (int)(BKOFCE_LEASE_TIME + tmNow - x.tmCurrent));
367437
lastWarning = tmNow;
368438
warningDelay *= 2;
369439
}
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
+ }
371448
}
372449
}
450
+#if defined(_WIN32)
451
+ backofficeWin32ThreadCleanup();
452
+#endif
373453
return;
374454
}
375455
376456
/*
377457
** This routine runs to do the backoffice processing. When adding new
378458
--- 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

Keyboard Shortcuts

Open search /
Next entry (timeline) j
Previous entry (timeline) k
Open focused entry Enter
Show this help ?
Toggle theme Top nav button