improved support of pthreads, changed behaviour of sanei_thread_kill(),

added functions sanei_thread_sendsig() and sanei_thread_get_status()
changed behaviour of sanei_thread_waitpid(), changed parameters
of sanei_thread_begin()
merge-requests/1/head
Gerhard Jaeger 2003-10-08 20:31:15 +00:00
rodzic 5204d4fed8
commit 25a38b2739
2 zmienionych plików z 177 dodań i 48 usunięć

Wyświetl plik

@ -71,43 +71,45 @@ extern void sanei_thread_init( void );
*/ */
extern SANE_Bool sanei_thread_is_forked( void ); extern SANE_Bool sanei_thread_is_forked( void );
/** <b>Do not use in backends</b> /** function to start
*
* Wrapper for @c fork.
*/ */
extern int sanei_thread_begin( void (*start)(void *arg), void* args ); extern int sanei_thread_begin( int (func)(void *args), void* args );
/** <b>Do not use in backends</b> /** function to terminate spawned process/thread. In pthread
* * context, pthread_cancel is used, in process contect, SIGTERM is send
* Wrapper for @c kill. * @param pid - the id of the task
*/ */
extern int sanei_thread_kill( int pid, int sig); extern int sanei_thread_kill( int pid );
/** <b>Do not use in backends</b> /** function to send signals to the thread/process
* * @param pid - the id of the task
* Wrapper for @c waitpid. * @param sig - the signal to send
*/ */
extern int sanei_thread_waitpid( int pid, int *stat_loc, int options); extern int sanei_thread_sendsig( int pid, int sig );
/** <b>Do not use in backends</b> /**
*
* Wrapper for @c wait.
*/ */
extern int sanei_thread_wait( int *stat_loc); extern int sanei_thread_waitpid( int pid, int *status );
/** function to return the current status of the spawned function
* @param pid - the id of the task
*/
extern SANE_Status sanei_thread_get_status( int pid );
/* @} */ /* @} */
/** Reader process function. /** Reader process function.
* *
* This wrapper is necessary if a backend's reader process need more than one * This wrapper is necessary if a backend's reader process need more than one
* argument. Add a function to you backend with this name and let it call your * argument. Add a function to your backend with this name and let it call your
* own reader process. See mustek.c for an example. * own reader process. See mustek.c for an example.
*/ */
#ifdef HAVE_OS2_H #ifdef HAVE_OS2_H
static void os2_reader_process( void* data); static void os2_reader_process( void* data);
#define fork() sanei_thread_begin( os2_reader_process) #define fork() sanei_thread_begin(os2_reader_process)
#define kill( a, b) sanei_thread_kill( a,b) #define kill(a, b) sanei_thread_kill( a )
#define waitpid( a, b, c) sanei_thread_waitpid( a, b, c) #define waitpid(a, b, c) sanei_thread_waitpid( a, b )
#endif #endif
#endif /* sanei_thread_h */ #endif /* sanei_thread_h */

Wyświetl plik

@ -1,6 +1,6 @@
/* sane - Scanner Access Now Easy. /* sane - Scanner Access Now Easy.
Copyright (C) 1998-2001 Yuri Dario Copyright (C) 1998-2001 Yuri Dario
Copyright (C) 2003 Gerhard Jaeger Copyright (C) 2003 Gerhard Jaeger (pthread/process support)
This file is part of the SANE package. This file is part of the SANE package.
This program is free software; you can redistribute it and/or This program is free software; you can redistribute it and/or
@ -39,17 +39,22 @@
whether to permit this exception to apply to your modifications. whether to permit this exception to apply to your modifications.
If you do not wish that, delete this exception notice. If you do not wish that, delete this exception notice.
OS/2
Helper functions for the OS/2 port (using threads instead of forked Helper functions for the OS/2 port (using threads instead of forked
processes). Don't use them in the backends, they are used automatically by processes). Don't use them in the backends, they are used automatically by
macros. macros.
Added pthread support (as found in hp-handle.c) - Gerhard Jaeger Other OS:
use this lib, if you intend to let run your reader function within its own
task (thread or process). Depending on the OS and/or the configure settings
pthread or fork is used to achieve this goal.
*/ */
#include "../include/sane/config.h" #include "../include/sane/config.h"
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <errno.h>
#ifdef HAVE_UNISTD_H #ifdef HAVE_UNISTD_H
# include <unistd.h> # include <unistd.h>
#endif #endif
@ -85,48 +90,112 @@ sanei_thread_init( void )
* *
*/ */
int int
sanei_thread_begin( void (*start)(void *arg), void* args ) sanei_thread_begin( void (*func)(void *args), void* args )
{ {
return _beginthread( start, NULL, 1024*1024, args ); return _beginthread( func, NULL, 1024*1024, args );
} }
int int
sanei_thread_kill( int pid, int sig) sanei_thread_kill( int pid )
{ {
return DosKillThread( pid); return DosKillThread(pid);
} }
int int
sanei_thread_waitpid( int pid, int *stat_loc, int options) sanei_thread_waitpid( int pid, int *status )
{ {
if (stat_loc) if (status
*stat_loc = 0; *status = 0;
return pid; /* DosWaitThread( (TID*) &pid, DCWW_WAIT);*/ return pid; /* DosWaitThread( (TID*) &pid, DCWW_WAIT);*/
} }
int int
sanei_thread_wait( int *stat_loc) sanei_thread_sendsig( int pid, int sig )
{ {
*stat_loc = 0; return 0;
return -1; /* return error because I don't know child pid */ }
int
sanei_thread_get_status( int pid )
{
return 0;
} }
#else /* HAVE_OS2_H */ #else /* HAVE_OS2_H */
#ifdef USE_PTHREAD #ifdef USE_PTHREAD
# include <signal.h>
# include <pthread.h> # include <pthread.h>
#else #else
# include <sys/wait.h> # include <sys/wait.h>
#endif #endif
#ifdef USE_PTHREAD
typedef struct {
int (*func)( void* );
void *func_data;
} ThreadDataDef, *pThreadDataDef;
static void*
local_thread( void *arg )
{
static int status;
int old;
pThreadDataDef td = (pThreadDataDef)arg;
DBG( 2, "thread started, calling func() now...\n" );
pthread_setcancelstate( PTHREAD_CANCEL_ENABLE, &old );
pthread_setcanceltype( PTHREAD_CANCEL_ASYNCHRONOUS, &old );
status = td->func( td->func_data );
DBG( 2, "func() done - status = %d\n", status );
/* return the status, so pthread_join is able to get it*/
pthread_exit((void*)&status );
}
#else /* the process stuff */
static int
eval_wp_result( int pid, int wpres, int pf )
{
int retval = SANE_STATUS_IO_ERROR;
if( wpres == pid ) {
if( WIFEXITED(pf)) {
retval = WEXITSTATUS(pf);
} else {
if( !WIFSIGNALED(pf)) {
retval = SANE_STATUS_GOOD;
} else {
DBG( 1, "Child terminated by signal %d\n", WTERMSIG(pf));
if( WTERMSIG(pf) == SIGTERM )
retval = SANE_STATUS_GOOD;
}
}
}
return retval;
}
#endif
int int
sanei_thread_begin( void (*start)(void *arg), void* args ) sanei_thread_begin( int (func)(void *args), void* args )
{ {
int pid; int pid;
#ifdef USE_PTHREAD #ifdef USE_PTHREAD
pthread_t thread; pthread_t thread;
ThreadDataDef td;
pid = pthread_create( &thread, NULL, start, args ); td.func = func;
td.func_data = args;
pid = pthread_create( &thread, NULL, local_thread, &td );
if ( pid != 0 ) { if ( pid != 0 ) {
DBG( 1, "pthread_create() failed with %d\n", pid ); DBG( 1, "pthread_create() failed with %d\n", pid );
@ -137,7 +206,6 @@ sanei_thread_begin( void (*start)(void *arg), void* args )
return (int)thread; return (int)thread;
#else #else
pid = fork(); pid = fork();
if( pid < 0 ) { if( pid < 0 ) {
DBG( 1, "fork() failed\n" ); DBG( 1, "fork() failed\n" );
return -1; return -1;
@ -146,9 +214,7 @@ sanei_thread_begin( void (*start)(void *arg), void* args )
if( pid == 0 ) { if( pid == 0 ) {
/* run in child context... */ /* run in child context... */
int status = 0; int status = func( args );
start( args );
/* don't use exit() since that would run the atexit() handlers */ /* don't use exit() since that would run the atexit() handlers */
_exit( status ); _exit( status );
@ -160,31 +226,93 @@ sanei_thread_begin( void (*start)(void *arg), void* args )
} }
int int
sanei_thread_kill( int pid, int sig) sanei_thread_kill( int pid )
{ {
DBG(2, "sanei_thread_kill() will kill %d\n", (int)pid); DBG(2, "sanei_thread_kill() will kill %d\n", (int)pid);
#ifdef USE_PTHREAD #ifdef USE_PTHREAD
return pthread_cancel((pthread_t)pid);
#else
return kill( pid, SIGTERM );
#endif
}
int
sanei_thread_sendsig( int pid, int sig )
{
#ifdef USE_PTHREAD
DBG(2, "sanei_thread_sendsig() %d to thread(id=%d)\n", sig, pid);
return pthread_kill((pthread_t)pid, sig ); return pthread_kill((pthread_t)pid, sig );
#else #else
DBG(2, "sanei_thread_sendsig() %d to process (id=%d)\n", sig, pid);
return kill( pid, sig ); return kill( pid, sig );
#endif #endif
} }
int int
sanei_thread_waitpid( int pid, int *stat_loc, int options ) sanei_thread_waitpid( int pid, int *status )
{ {
if (stat_loc)
*stat_loc = 0;
#ifdef USE_PTHREAD #ifdef USE_PTHREAD
int *ls;
#else
int ls;
#endif
int result;
if (status)
*status = 0;
_VAR_NOT_USED( options ); DBG(2, "sanei_thread_waitpid() - %d\n", (int)pid);
#ifdef USE_PTHREAD
result = pthread_join((pthread_t)pid, (void*)&ls );
if( 0 == pthread_join((pthread_t)pid, (void*)stat_loc )) if( 0 == result ) {
DBG(2, "* detaching thread\n" );
pthread_detach((pthread_t)pid ); pthread_detach((pthread_t)pid );
if( PTHREAD_CANCELED == ls ) {
DBG(2, "* thread has been canceled!\n" );
* status = SANE_STATUS_GOOD;
} else {
*status = *ls;
}
DBG(2, "* result = %d\n", *status );
}
/* should return */
return pid; return pid;
#else #else
return waitpid( pid, stat_loc, options ); result = waitpid( pid, &ls, 0 );
if((result < 0) && (errno == ECHILD)) {
if( status )
* status = SANE_STATUS_GOOD;
result = pid;
} else {
if (status) {
*status = eval_wp_result( pid, result, ls );
}
}
return result;
#endif
}
SANE_Status
sanei_thread_get_status( int pid )
{
#ifdef USE_PTHREAD
_VAR_NOT_USED( pid );
return SANE_STATUS_GOOD;
#else
int ls, stat, result;
stat = SANE_STATUS_IO_ERROR;
if( pid > 0 ) {
result = waitpid( pid, &ls, WNOHANG );
stat = eval_wp_result( pid, result, ls );
}
return stat;
#endif #endif
} }
@ -199,4 +327,3 @@ sanei_thread_is_forked( void )
} }
#endif /* HAVE_OS2_H */ #endif /* HAVE_OS2_H */