• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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