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_kill((pthread_t)pid, 10);
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 #endif
348
349 DBG( 2, "thread started, calling func() now...\n" );
350
351 status = ltd->func( ltd->func_data );
352
353 /* so sanei_thread_get_status() will work correctly... */
354 ltd->status = status;
355
356 DBG( 2, "func() done - status = %d\n", status );
357
358 /* return the status, so pthread_join is able to get it*/
359 pthread_exit((void*)&status );
360 }
361
362 /**
363 */
364 static void
restore_sigpipe(void)365 restore_sigpipe( void )
366 {
367 #ifdef SIGPIPE
368 struct sigaction act;
369
370 if( sigaction( SIGPIPE, NULL, &act ) == 0 ) {
371
372 if( act.sa_handler == SIG_IGN ) {
373 sigemptyset( &act.sa_mask );
374 act.sa_flags = 0;
375 act.sa_handler = SIG_DFL;
376
377 DBG( 2, "restoring SIGPIPE to SIG_DFL\n" );
378 sigaction( SIGPIPE, &act, NULL );
379 }
380 }
381 #endif
382 }
383
384 #else /* the process stuff */
385
386 static int
eval_wp_result(SANE_Pid pid,int wpres,int pf)387 eval_wp_result( SANE_Pid pid, int wpres, int pf )
388 {
389 int retval = SANE_STATUS_IO_ERROR;
390
391 if( wpres == pid ) {
392
393 if( WIFEXITED(pf)) {
394 retval = WEXITSTATUS(pf);
395 } else {
396
397 if( !WIFSIGNALED(pf)) {
398 retval = SANE_STATUS_GOOD;
399 } else {
400 DBG( 1, "Child terminated by signal %d\n", WTERMSIG(pf));
401 if( WTERMSIG(pf) == SIGTERM )
402 retval = SANE_STATUS_GOOD;
403 }
404 }
405 }
406 return retval;
407 }
408 #endif
409
410 SANE_Pid
sanei_thread_begin(int (func)(void * args),void * args)411 sanei_thread_begin( int (func)(void *args), void* args )
412 {
413 #ifdef USE_PTHREAD
414 int result;
415 pthread_t thread;
416 #ifdef SIGPIPE
417 struct sigaction act;
418
419 /* if signal handler for SIGPIPE is SIG_DFL, replace by SIG_IGN */
420 if( sigaction( SIGPIPE, NULL, &act ) == 0 ) {
421
422 if( act.sa_handler == SIG_DFL ) {
423 sigemptyset( &act.sa_mask );
424 act.sa_flags = 0;
425 act.sa_handler = SIG_IGN;
426
427 DBG( 2, "setting SIGPIPE to SIG_IGN\n" );
428 sigaction( SIGPIPE, &act, NULL );
429 }
430 }
431 #endif
432
433 td.func = func;
434 td.func_data = args;
435
436 result = pthread_create( &thread, NULL, local_thread, &td );
437 usleep( 1 );
438
439 if ( result != 0 ) {
440 DBG( 1, "pthread_create() failed with %d\n", result );
441 sanei_thread_set_invalid(&thread);
442 }
443 else
444 DBG( 2, "pthread_create() created thread %ld\n",
445 sanei_thread_pid_to_long(thread) );
446
447 return (SANE_Pid)thread;
448 #else
449 SANE_Pid pid;
450 pid = fork();
451 if( pid < 0 ) {
452 DBG( 1, "fork() failed\n" );
453 return -1;
454 }
455
456 if( pid == 0 ) {
457
458 /* run in child context... */
459 int status = func( args );
460
461 /* don't use exit() since that would run the atexit() handlers */
462 _exit( status );
463 }
464
465 /* parents return */
466 return pid;
467 #endif
468 }
469
470 int
sanei_thread_sendsig(SANE_Pid pid,int sig)471 sanei_thread_sendsig( SANE_Pid pid, int sig )
472 {
473 DBG(2, "sanei_thread_sendsig() %d to thread (id=%ld)\n", sig,
474 sanei_thread_pid_to_long(pid));
475 #ifdef USE_PTHREAD
476 return pthread_kill( (pthread_t)pid, sig );
477 #else
478 return kill( pid, sig );
479 #endif
480 }
481
482 SANE_Pid
sanei_thread_waitpid(SANE_Pid pid,int * status)483 sanei_thread_waitpid( SANE_Pid pid, int *status )
484 {
485 #ifdef USE_PTHREAD
486 int *ls;
487 #else
488 int ls;
489 #endif
490 SANE_Pid result = pid;
491 int stat;
492
493 stat = 0;
494
495 DBG(2, "sanei_thread_waitpid() - %ld\n",
496 sanei_thread_pid_to_long(pid));
497 #ifdef USE_PTHREAD
498 int rc;
499 rc = pthread_join( (pthread_t)pid, (void*)&ls );
500
501 if( 0 == rc ) {
502 if( PTHREAD_CANCELED == ls ) {
503 DBG(2, "* thread has been canceled!\n" );
504 stat = SANE_STATUS_GOOD;
505 } else {
506 stat = *ls;
507 }
508 DBG(2, "* result = %d (%p)\n", stat, (void*)status );
509 result = pid;
510 }
511 if ( EDEADLK == rc ) {
512 if ( (pthread_t)pid != pthread_self() ) {
513 /* call detach in any case to make sure that the thread resources
514 * will be freed, when the thread has terminated
515 */
516 DBG(2, "* detaching thread(%ld)\n",
517 sanei_thread_pid_to_long(pid) );
518 pthread_detach((pthread_t)pid);
519 }
520 }
521 if (status)
522 *status = stat;
523
524 restore_sigpipe();
525 #else
526 result = waitpid( pid, &ls, 0 );
527 if((result < 0) && (errno == ECHILD)) {
528 stat = SANE_STATUS_GOOD;
529 result = pid;
530 } else {
531 stat = eval_wp_result( pid, result, ls );
532 DBG(2, "* result = %d (%p)\n", stat, (void*)status );
533 }
534 if( status )
535 *status = stat;
536 #endif
537 return result;
538 }
539
540 #endif /* HAVE_OS2_H */
541
542 SANE_Status
sanei_thread_get_status(SANE_Pid pid)543 sanei_thread_get_status( SANE_Pid pid )
544 {
545 #if defined USE_PTHREAD || defined HAVE_OS2_H || defined __BEOS__
546 _VAR_NOT_USED( pid );
547
548 return td.status;
549 #else
550 int ls, stat, result;
551
552 stat = SANE_STATUS_IO_ERROR;
553 if( pid > 0 ) {
554
555 result = waitpid( pid, &ls, WNOHANG );
556
557 stat = eval_wp_result( pid, result, ls );
558 }
559 return stat;
560 #endif
561 }
562
563 /* END sanei_thread.c .......................................................*/
564