1 /* sane - Scanner Access Now Easy.
2 Copyright (C) 1998-2001 Yuri Dario
3 Copyright (C) 2003-2004 Gerhard Jaeger (pthread/process support)
4 This file is part of the SANE package.
5
6 This program is free software; you can redistribute it and/or
7 modify it under the terms of the GNU General Public License as
8 published by the Free Software Foundation; either version 2 of the
9 License, or (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program. If not, see <https://www.gnu.org/licenses/>.
18
19 As a special exception, the authors of SANE give permission for
20 additional uses of the libraries contained in this release of SANE.
21
22 The exception is that, if you link a SANE library with other files
23 to produce an executable, this does not by itself cause the
24 resulting executable to be covered by the GNU General Public
25 License. Your use of that executable is in no way restricted on
26 account of linking the SANE library code into it.
27
28 This exception does not, however, invalidate any other reasons why
29 the executable file might be covered by the GNU General Public
30 License.
31
32 If you submit changes to SANE to the maintainers to be included in
33 a subsequent release, you agree by submitting the changes that
34 those changes may be distributed with this exception intact.
35
36 If you write modifications of your own for SANE, it is your choice
37 whether to permit this exception to apply to your modifications.
38 If you do not wish that, delete this exception notice.
39
40 OS/2
41 Helper functions for the OS/2 port (using threads instead of forked
42 processes). Don't use them in the backends, they are used automatically by
43 macros.
44
45 Other OS:
46 use this lib, if you intend to let run your reader function within its own
47 task (thread or process). Depending on the OS and/or the configure settings
48 pthread or fork is used to achieve this goal.
49 */
50
51 #include "../include/sane/config.h"
52
53 #include <stdio.h>
54 #include <stdlib.h>
55 #include <string.h>
56 #include <errno.h>
57 #include <signal.h>
58 #ifdef HAVE_UNISTD_H
59 # include <unistd.h>
60 #endif
61 #ifdef HAVE_OS2_H
62 # define INCL_DOSPROCESS
63 # include <os2.h>
64 #endif
65 #ifdef __BEOS__
66 # undef USE_PTHREAD /* force */
67 # include <kernel/OS.h>
68 #endif
69 #if !defined USE_PTHREAD && !defined HAVE_OS2_H && !defined __BEOS__
70 # include <sys/wait.h>
71 #endif
72
73 #define BACKEND_NAME sanei_thread /**< name of this module for debugging */
74
75 #include "../include/sane/sane.h"
76 #include "../include/sane/sanei_debug.h"
77 #include "../include/sane/sanei_thread.h"
78
79 #ifndef _VAR_NOT_USED
80 # define _VAR_NOT_USED(x) ((x)=(x))
81 #endif
82
83 typedef struct {
84
85 int (*func)( void* );
86 SANE_Status status;
87 void *func_data;
88
89 } ThreadDataDef, *pThreadDataDef;
90
91 static ThreadDataDef td;
92
93 /** for init issues - here only for the debug output
94 */
95 void
sanei_thread_init(void)96 sanei_thread_init( void )
97 {
98 DBG_INIT();
99
100 memset( &td, 0, sizeof(ThreadDataDef));
101 td.status = SANE_STATUS_GOOD;
102 }
103
104 SANE_Bool
sanei_thread_is_forked(void)105 sanei_thread_is_forked( void )
106 {
107 #if defined USE_PTHREAD || defined HAVE_OS2_H || defined __BEOS__
108 return SANE_FALSE;
109 #else
110 return SANE_TRUE;
111 #endif
112 }
113
114 /* Use this to mark a SANE_Pid as invalid instead of marking with -1.
115 */
116 #ifdef USE_PTHREAD
117 static void
sanei_thread_set_invalid(SANE_Pid * pid)118 sanei_thread_set_invalid( SANE_Pid *pid )
119 {
120
121 #ifdef WIN32
122 #ifdef WINPTHREAD_API
123 *pid = (pthread_t) 0;
124 #else
125 pid->p = 0;
126 #endif
127 #else
128 *pid = (pthread_t) -1;
129 #endif
130 }
131 #endif
132
133 /* Return if PID is a valid PID or not. */
134 SANE_Bool
sanei_thread_is_valid(SANE_Pid pid)135 sanei_thread_is_valid( SANE_Pid pid )
136 {
137 SANE_Bool rc = SANE_TRUE;
138
139 #ifdef WIN32
140 #ifdef WINPTHREAD_API
141 if (pid == 0)
142 #else
143 if (pid.p == 0)
144 #endif
145 rc = SANE_FALSE;
146 #else
147 if (pid == (SANE_Pid) -1)
148 rc = SANE_FALSE;
149 #endif
150
151 return rc;
152 }
153
154 /* pthread_t is not an integer on all platform. Do our best to return
155 * a PID-like value from structure. On platforms were it is an integer,
156 * return that.
157 */
158 static long
sanei_thread_pid_to_long(SANE_Pid pid)159 sanei_thread_pid_to_long( SANE_Pid pid )
160 {
161 int rc;
162
163 #ifdef WIN32
164 #ifdef WINPTHREAD_API
165 rc = (long) pid;
166 #else
167 rc = pid.p;
168 #endif
169 #else
170 rc = (long) pid;
171 #endif
172
173 return rc;
174 }
175
176 int
sanei_thread_kill(SANE_Pid pid)177 sanei_thread_kill( SANE_Pid pid )
178 {
179 DBG(2, "sanei_thread_kill() will kill %ld\n",
180 sanei_thread_pid_to_long(pid));
181 #ifdef USE_PTHREAD
182 #if defined (__APPLE__) && defined (__MACH__)
183 return pthread_kill((pthread_t)pid, SIGUSR2);
184 #else
185 return pthread_cancel((pthread_t)pid);
186 #endif
187 #elif defined HAVE_OS2_H
188 return DosKillThread(pid);
189 #else
190 return kill( pid, SIGTERM );
191 #endif
192 }
193
194 #ifdef HAVE_OS2_H
195
196 static void
local_thread(void * arg)197 local_thread( void *arg )
198 {
199 pThreadDataDef ltd = (pThreadDataDef)arg;
200
201 DBG( 2, "thread started, calling func() now...\n" );
202 ltd->status = ltd->func( ltd->func_data );
203
204 DBG( 2, "func() done - status = %d\n", ltd->status );
205 _endthread();
206 }
207
208 /*
209 * starts a new thread or process
210 * parameters:
211 * star address of reader function
212 * args pointer to scanner data structure
213 *
214 */
215 SANE_Pid
sanei_thread_begin(int (* func)(void * args),void * args)216 sanei_thread_begin( int (*func)(void *args), void* args )
217 {
218 SANE_Pid pid;
219
220 td.func = func;
221 td.func_data = args;
222
223 pid = _beginthread( local_thread, NULL, 1024*1024, (void*)&td );
224 if ( pid == -1 ) {
225 DBG( 1, "_beginthread() failed\n" );
226 return -1;
227 }
228
229 DBG( 2, "_beginthread() created thread %d\n", pid );
230 return pid;
231 }
232
233 SANE_Pid
sanei_thread_waitpid(SANE_Pid pid,int * status)234 sanei_thread_waitpid( SANE_Pid pid, int *status )
235 {
236 if (status)
237 *status = 0;
238 return pid; /* DosWaitThread( (TID*) &pid, DCWW_WAIT);*/
239 }
240
241 int
sanei_thread_sendsig(SANE_Pid pid,int sig)242 sanei_thread_sendsig( SANE_Pid pid, int sig )
243 {
244 return 0;
245 }
246
247 #elif defined __BEOS__
248
249 static int32
local_thread(void * arg)250 local_thread( void *arg )
251 {
252 pThreadDataDef ltd = (pThreadDataDef)arg;
253
254 DBG( 2, "thread started, calling func() now...\n" );
255 ltd->status = ltd->func( ltd->func_data );
256
257 DBG( 2, "func() done - status = %d\n", ltd->status );
258 return ltd->status;
259 }
260
261 /*
262 * starts a new thread or process
263 * parameters:
264 * star address of reader function
265 * args pointer to scanner data structure
266 *
267 */
268 SANE_Pid
sanei_thread_begin(int (* func)(void * args),void * args)269 sanei_thread_begin( int (*func)(void *args), void* args )
270 {
271 SANE_Pid pid;
272
273 td.func = func;
274 td.func_data = args;
275
276 pid = spawn_thread( local_thread, "sane thread (yes they can be)", B_NORMAL_PRIORITY, (void*)&td );
277 if ( pid < B_OK ) {
278 DBG( 1, "spawn_thread() failed\n" );
279 return -1;
280 }
281 if ( resume_thread(pid) < B_OK ) {
282 DBG( 1, "resume_thread() failed\n" );
283 return -1;
284 }
285
286 DBG( 2, "spawn_thread() created thread %d\n", pid );
287 return pid;
288 }
289
290 SANE_Pid
sanei_thread_waitpid(SANE_Pid pid,int * status)291 sanei_thread_waitpid( SANE_Pid pid, int *status )
292 {
293 int32 st;
294 if ( wait_for_thread(pid, &st) < B_OK )
295 return -1;
296 if ( status )
297 *status = (int)st;
298 return pid;
299 }
300
301 int
sanei_thread_sendsig(SANE_Pid pid,int sig)302 sanei_thread_sendsig( SANE_Pid pid, int sig )
303 {
304 if (sig == SIGKILL)
305 sig = SIGKILLTHR;
306 return kill(pid, sig);
307 }
308
309 #else /* HAVE_OS2_H, __BEOS__ */
310
311 #ifdef USE_PTHREAD
312
313 /* seems to be undefined in MacOS X */
314 #ifndef PTHREAD_CANCELED
315 # define PTHREAD_CANCELED ((void *) -1)
316 #endif
317
318 /**
319 */
320 #if defined (__APPLE__) && defined (__MACH__)
321 static void
thread_exit_handler(int signo)322 thread_exit_handler( int signo )
323 {
324 DBG( 2, "signal(%i) caught, calling pthread_exit now...\n", signo );
325 pthread_exit( PTHREAD_CANCELED );
326 }
327 #endif
328
329
330 static void*
local_thread(void * arg)331 local_thread( void *arg )
332 {
333 static int status;
334 pThreadDataDef ltd = (pThreadDataDef)arg;
335
336 #if defined (__APPLE__) && defined (__MACH__)
337 struct sigaction act;
338
339 sigemptyset(&(act.sa_mask));
340 act.sa_flags = 0;
341 act.sa_handler = thread_exit_handler;
342 sigaction( SIGUSR2, &act, 0 );
343 #else
344 int old;
345
346 pthread_setcancelstate( PTHREAD_CANCEL_ENABLE, &old );
347 pthread_setcanceltype ( PTHREAD_CANCEL_ASYNCHRONOUS, &old );
348 #endif
349
350 DBG( 2, "thread started, calling func() now...\n" );
351
352 status = ltd->func( ltd->func_data );
353
354 /* so sanei_thread_get_status() will work correctly... */
355 ltd->status = status;
356
357 DBG( 2, "func() done - status = %d\n", status );
358
359 /* return the status, so pthread_join is able to get it*/
360 pthread_exit((void*)&status );
361 }
362
363 /**
364 */
365 static void
restore_sigpipe(void)366 restore_sigpipe( void )
367 {
368 #ifdef SIGPIPE
369 struct sigaction act;
370
371 if( sigaction( SIGPIPE, NULL, &act ) == 0 ) {
372
373 if( act.sa_handler == SIG_IGN ) {
374 sigemptyset( &act.sa_mask );
375 act.sa_flags = 0;
376 act.sa_handler = SIG_DFL;
377
378 DBG( 2, "restoring SIGPIPE to SIG_DFL\n" );
379 sigaction( SIGPIPE, &act, NULL );
380 }
381 }
382 #endif
383 }
384
385 #else /* the process stuff */
386
387 static int
eval_wp_result(SANE_Pid pid,int wpres,int pf)388 eval_wp_result( SANE_Pid pid, int wpres, int pf )
389 {
390 int retval = SANE_STATUS_IO_ERROR;
391
392 if( wpres == pid ) {
393
394 if( WIFEXITED(pf)) {
395 retval = WEXITSTATUS(pf);
396 } else {
397
398 if( !WIFSIGNALED(pf)) {
399 retval = SANE_STATUS_GOOD;
400 } else {
401 DBG( 1, "Child terminated by signal %d\n", WTERMSIG(pf));
402 if( WTERMSIG(pf) == SIGTERM )
403 retval = SANE_STATUS_GOOD;
404 }
405 }
406 }
407 return retval;
408 }
409 #endif
410
411 SANE_Pid
sanei_thread_begin(int (func)(void * args),void * args)412 sanei_thread_begin( int (func)(void *args), void* args )
413 {
414 #ifdef USE_PTHREAD
415 int result;
416 pthread_t thread;
417 #ifdef SIGPIPE
418 struct sigaction act;
419
420 /* if signal handler for SIGPIPE is SIG_DFL, replace by SIG_IGN */
421 if( sigaction( SIGPIPE, NULL, &act ) == 0 ) {
422
423 if( act.sa_handler == SIG_DFL ) {
424 sigemptyset( &act.sa_mask );
425 act.sa_flags = 0;
426 act.sa_handler = SIG_IGN;
427
428 DBG( 2, "setting SIGPIPE to SIG_IGN\n" );
429 sigaction( SIGPIPE, &act, NULL );
430 }
431 }
432 #endif
433
434 td.func = func;
435 td.func_data = args;
436
437 result = pthread_create( &thread, NULL, local_thread, &td );
438 usleep( 1 );
439
440 if ( result != 0 ) {
441 DBG( 1, "pthread_create() failed with %d\n", result );
442 sanei_thread_set_invalid(&thread);
443 }
444 else
445 DBG( 2, "pthread_create() created thread %ld\n",
446 sanei_thread_pid_to_long(thread) );
447
448 return (SANE_Pid)thread;
449 #else
450 SANE_Pid pid;
451 pid = fork();
452 if( pid < 0 ) {
453 DBG( 1, "fork() failed\n" );
454 return -1;
455 }
456
457 if( pid == 0 ) {
458
459 /* run in child context... */
460 int status = func( args );
461
462 /* don't use exit() since that would run the atexit() handlers */
463 _exit( status );
464 }
465
466 /* parents return */
467 return pid;
468 #endif
469 }
470
471 int
sanei_thread_sendsig(SANE_Pid pid,int sig)472 sanei_thread_sendsig( SANE_Pid pid, int sig )
473 {
474 DBG(2, "sanei_thread_sendsig() %d to thread (id=%ld)\n", sig,
475 sanei_thread_pid_to_long(pid));
476 #ifdef USE_PTHREAD
477 return pthread_kill( (pthread_t)pid, sig );
478 #else
479 return kill( pid, sig );
480 #endif
481 }
482
483 SANE_Pid
sanei_thread_waitpid(SANE_Pid pid,int * status)484 sanei_thread_waitpid( SANE_Pid pid, int *status )
485 {
486 #ifdef USE_PTHREAD
487 int *ls;
488 #else
489 int ls;
490 #endif
491 SANE_Pid result = pid;
492 int stat;
493
494 stat = 0;
495
496 DBG(2, "sanei_thread_waitpid() - %ld\n",
497 sanei_thread_pid_to_long(pid));
498 #ifdef USE_PTHREAD
499 int rc;
500 rc = pthread_join( (pthread_t)pid, (void*)&ls );
501
502 if( 0 == rc ) {
503 if( PTHREAD_CANCELED == ls ) {
504 DBG(2, "* thread has been canceled!\n" );
505 stat = SANE_STATUS_GOOD;
506 } else {
507 stat = *ls;
508 }
509 DBG(2, "* result = %d (%p)\n", stat, (void*)status );
510 result = pid;
511 }
512 if ( EDEADLK == rc ) {
513 if ( (pthread_t)pid != pthread_self() ) {
514 /* call detach in any case to make sure that the thread resources
515 * will be freed, when the thread has terminated
516 */
517 DBG(2, "* detaching thread(%ld)\n",
518 sanei_thread_pid_to_long(pid) );
519 pthread_detach((pthread_t)pid);
520 }
521 }
522 if (status)
523 *status = stat;
524
525 restore_sigpipe();
526 #else
527 result = waitpid( pid, &ls, 0 );
528 if((result < 0) && (errno == ECHILD)) {
529 stat = SANE_STATUS_GOOD;
530 result = pid;
531 } else {
532 stat = eval_wp_result( pid, result, ls );
533 DBG(2, "* result = %d (%p)\n", stat, (void*)status );
534 }
535 if( status )
536 *status = stat;
537 #endif
538 return result;
539 }
540
541 #endif /* HAVE_OS2_H */
542
543 SANE_Status
sanei_thread_get_status(SANE_Pid pid)544 sanei_thread_get_status( SANE_Pid pid )
545 {
546 #if defined USE_PTHREAD || defined HAVE_OS2_H || defined __BEOS__
547 _VAR_NOT_USED( pid );
548
549 return td.status;
550 #else
551 int ls, stat, result;
552
553 stat = SANE_STATUS_IO_ERROR;
554 if( pid > 0 ) {
555
556 result = waitpid( pid, &ls, WNOHANG );
557
558 stat = eval_wp_result( pid, result, ls );
559 }
560 return stat;
561 #endif
562 }
563
564 /* END sanei_thread.c .......................................................*/
565