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