Merge branch 'sanei_thread_fixup' into 'master'

Draft: sanei_thread: Draft fixup for sanei_thread issues.

See merge request sane-project/backends!750
merge-requests/750/merge
Ralph Little 2025-08-08 21:09:04 -07:00
commit 18a9fe8c4f
12 zmienionych plików z 272 dodań i 131 usunięć

Wyświetl plik

@ -3490,7 +3490,7 @@ do_cancel (Artec48U_Scanner * s, SANE_Bool closepipe)
res = sanei_thread_waitpid (s->reader_pid, 0); res = sanei_thread_waitpid (s->reader_pid, 0);
alarm (0); alarm (0);
if (res != s->reader_pid) if (!sanei_thread_pid_compare(res, s->reader_pid))
{ {
XDBG ((1, "sanei_thread_waitpid() failed !\n")); XDBG ((1, "sanei_thread_waitpid() failed !\n"));
} }

Wyświetl plik

@ -2033,8 +2033,9 @@ do_cancel (Coolscan_t * scanner)
/* ensure child knows it's time to stop: */ /* ensure child knows it's time to stop: */
sanei_thread_kill (scanner->reader_pid); sanei_thread_kill (scanner->reader_pid);
while (sanei_thread_waitpid(scanner->reader_pid, &exit_status) != while (!sanei_thread_pid_compare(sanei_thread_waitpid(scanner->reader_pid, &exit_status),
scanner->reader_pid ); scanner->reader_pid) )
;
sanei_thread_invalidate (scanner->reader_pid); sanei_thread_invalidate (scanner->reader_pid);
} }

Wyświetl plik

@ -90,7 +90,7 @@ struct hp_handle_s
static hp_bool_t static hp_bool_t
hp_handle_isScanning (HpHandle this) hp_handle_isScanning (HpHandle this)
{ {
return this->reader_pid != 0; return sanei_thread_is_valid(this->reader_pid);
} }
/* /*
@ -157,7 +157,7 @@ hp_handle_startReader (HpHandle this, HpScsi scsi)
int fds[2]; int fds[2];
sigset_t old_set; sigset_t old_set;
assert(this->reader_pid == 0); assert(!sanei_thread_is_valid(this->reader_pid));
this->cancelled = 0; this->cancelled = 0;
this->pipe_write_fd = this->pipe_read_fd = -1; this->pipe_write_fd = this->pipe_read_fd = -1;
@ -178,7 +178,7 @@ hp_handle_startReader (HpHandle this, HpScsi scsi)
/* Returning means to be in the parent or thread/fork failed */ /* Returning means to be in the parent or thread/fork failed */
this->reader_pid = sanei_thread_begin (this->child_forked ? reader_process : this->reader_pid = sanei_thread_begin (this->child_forked ? reader_process :
reader_thread, (void *) this); reader_thread, (void *) this);
if (this->reader_pid != 0) if (sanei_thread_is_valid (this->reader_pid))
{ {
/* Here we are in the parent */ /* Here we are in the parent */
sigprocmask(SIG_SETMASK, &old_set, 0); sigprocmask(SIG_SETMASK, &old_set, 0);
@ -190,8 +190,15 @@ hp_handle_startReader (HpHandle this, HpScsi scsi)
this->pipe_write_fd = -1; this->pipe_write_fd = -1;
} }
if (!sanei_thread_is_valid (this->reader_pid)) DBG (1, "start_reader: reader process %ld started\n",
{ sanei_thread_pid_to_long (this->reader_pid));
return SANE_STATUS_GOOD;
}
/*
* Error kicking off the reader.
*
*/
if (!this->child_forked) if (!this->child_forked)
{ {
close (this->pipe_write_fd); close (this->pipe_write_fd);
@ -200,19 +207,11 @@ hp_handle_startReader (HpHandle this, HpScsi scsi)
close (this->pipe_read_fd); close (this->pipe_read_fd);
this->pipe_read_fd = -1; this->pipe_read_fd = -1;
DBG(1, "hp_handle_startReader: fork() failed\n"); DBG (1, "hp_handle_startReader: fork()/thread start failed\n");
return SANE_STATUS_IO_ERROR; return SANE_STATUS_IO_ERROR;
} }
DBG(1, "start_reader: reader process %ld started\n", (long) this->reader_pid);
return SANE_STATUS_GOOD;
}
DBG(3, "Unexpected return from sanei_thread_begin()\n");
return SANE_STATUS_INVAL;
}
static SANE_Status static SANE_Status
hp_handle_stopScan (HpHandle this) hp_handle_stopScan (HpHandle this)
{ {
@ -221,10 +220,11 @@ hp_handle_stopScan (HpHandle this)
this->cancelled = 0; this->cancelled = 0;
this->bytes_left = 0; this->bytes_left = 0;
if (this->reader_pid) if (sanei_thread_is_valid(this->reader_pid))
{ {
int info; int info;
DBG(3, "hp_handle_stopScan: killing child (%ld)\n", (long) this->reader_pid); DBG(3, "hp_handle_stopScan: killing child (%ld)\n",
sanei_thread_pid_to_long(this->reader_pid));
sanei_thread_kill (this->reader_pid); sanei_thread_kill (this->reader_pid);
sanei_thread_waitpid(this->reader_pid, &info); sanei_thread_waitpid(this->reader_pid, &info);
@ -232,7 +232,7 @@ hp_handle_stopScan (HpHandle this)
WIFEXITED(info) ? "exited, status" : "signalled, signal", WIFEXITED(info) ? "exited, status" : "signalled, signal",
WIFEXITED(info) ? WEXITSTATUS(info) : WTERMSIG(info)); WIFEXITED(info) ? WEXITSTATUS(info) : WTERMSIG(info));
close(this->pipe_read_fd); close(this->pipe_read_fd);
this->reader_pid = 0; sanei_thread_invalidate(this->reader_pid);
if ( !FAILED( sanei_hp_scsi_new(&scsi, this->dev->sanedev.name)) ) if ( !FAILED( sanei_hp_scsi_new(&scsi, this->dev->sanedev.name)) )
{ {
@ -732,11 +732,11 @@ sanei_hp_handle_cancel (HpHandle this)
/* Therefore the read might not return until it is interrupted. */ /* Therefore the read might not return until it is interrupted. */
DBG(3,"sanei_hp_handle_cancel: compat flags: 0x%04x\n", DBG(3,"sanei_hp_handle_cancel: compat flags: 0x%04x\n",
(int)this->dev->compat); (int)this->dev->compat);
if ( (this->reader_pid) if (sanei_thread_is_valid (this->reader_pid)
&& (this->dev->compat & HP_COMPAT_OJ_1150C)) && (this->dev->compat & HP_COMPAT_OJ_1150C))
{ {
DBG(3,"sanei_hp_handle_cancel: send SIGTERM to child (%ld)\n", DBG(3,"sanei_hp_handle_cancel: send SIGTERM to child (%ld)\n",
(long) this->reader_pid); sanei_thread_pid_to_long(this->reader_pid));
sanei_thread_kill(this->reader_pid); sanei_thread_kill(this->reader_pid);
} }
} }

Wyświetl plik

@ -966,7 +966,7 @@ attachScanner (const char *devicename)
dev->devicename = strdup (devicename); dev->devicename = strdup (devicename);
dev->sfd = -1; dev->sfd = -1;
dev->last_scan = 0; dev->last_scan = 0;
dev->reader_pid = (SANE_Pid) -1; sanei_thread_invalidate(dev->reader_pid);
dev->pipe_r = dev->pipe_w = -1; dev->pipe_r = dev->pipe_w = -1;
dev->sane.name = dev->devicename; dev->sane.name = dev->devicename;

Wyświetl plik

@ -1258,7 +1258,7 @@ terminate_reader_task (pixma_sane_t * ss, int *exit_code)
if (ss->sp.source != PIXMA_SOURCE_ADF && ss->sp.source != PIXMA_SOURCE_ADFDUP) if (ss->sp.source != PIXMA_SOURCE_ADF && ss->sp.source != PIXMA_SOURCE_ADFDUP)
ss->idle = SANE_TRUE; ss->idle = SANE_TRUE;
if (result == pid) if (sanei_thread_pid_compare(result, pid))
{ {
if (exit_code) if (exit_code)
*exit_code = status; *exit_code = status;
@ -1291,7 +1291,8 @@ start_reader_task (pixma_sane_t * ss)
if (sanei_thread_is_valid (ss->reader_taskid)) if (sanei_thread_is_valid (ss->reader_taskid))
{ {
PDBG (pixma_dbg PDBG (pixma_dbg
(1, "BUG:reader_taskid(%ld) != -1\n", (long) ss->reader_taskid)); (1, "BUG:reader_taskid(%ld) != -1\n",
sanei_thread_pid_to_long(ss->reader_taskid)));
terminate_reader_task (ss, NULL); terminate_reader_task (ss, NULL);
} }
if (pipe (fds) == -1) if (pipe (fds) == -1)
@ -1327,7 +1328,8 @@ start_reader_task (pixma_sane_t * ss)
PDBG (pixma_dbg (1, "ERROR:unable to start reader task\n")); PDBG (pixma_dbg (1, "ERROR:unable to start reader task\n"));
return PIXMA_ENOMEM; return PIXMA_ENOMEM;
} }
PDBG (pixma_dbg (3, "Reader task id=%ld (%s)\n", (long) pid, PDBG (pixma_dbg (3, "Reader task id=%ld (%s)\n",
sanei_thread_pid_to_long(pid),
(is_forked) ? "forked" : "threaded")); (is_forked) ? "forked" : "threaded"));
ss->reader_taskid = pid; ss->reader_taskid = pid;
return 0; return 0;

Wyświetl plik

@ -591,7 +591,7 @@ do_cancel( Plustek_Scanner *scanner, SANE_Bool closepipe )
res = sanei_thread_waitpid( scanner->reader_pid, 0 ); res = sanei_thread_waitpid( scanner->reader_pid, 0 );
alarm(0); alarm(0);
if( res != scanner->reader_pid ) { if(!sanei_thread_pid_compare(res, scanner->reader_pid)) {
DBG( _DBG_PROC,"sanei_thread_waitpid() failed !\n"); DBG( _DBG_PROC,"sanei_thread_waitpid() failed !\n");
/* do it the hard way...*/ /* do it the hard way...*/

Wyświetl plik

@ -493,7 +493,7 @@ static SANE_Status do_cancel( Plustek_Scanner *scanner, SANE_Bool closepipe )
res = sanei_thread_waitpid( scanner->reader_pid, 0 ); res = sanei_thread_waitpid( scanner->reader_pid, 0 );
alarm(0); alarm(0);
if( res != scanner->reader_pid ) { if( !sanei_thread_pid_compare(res, scanner->reader_pid) ) {
DBG( _DBG_PROC,"sanei_thread_waitpid() failed !\n"); DBG( _DBG_PROC,"sanei_thread_waitpid() failed !\n");
/* do it the hard way...*/ /* do it the hard way...*/

Wyświetl plik

@ -1893,7 +1893,7 @@ void sane_cancel (SANE_Handle h)
res = sanei_thread_waitpid( pss->child, 0 ); res = sanei_thread_waitpid( pss->child, 0 );
alarm(0); alarm(0);
if( res != pss->child ) { if( !sanei_thread_pid_compare(res, pss->child) ) {
DBG( DL_MINOR_ERROR,"sanei_thread_waitpid() failed !\n"); DBG( DL_MINOR_ERROR,"sanei_thread_waitpid() failed !\n");
/* do it the hard way...*/ /* do it the hard way...*/

Wyświetl plik

@ -1585,7 +1585,7 @@ finish_pass (Test_Device * test_device)
SANE_Pid pid; SANE_Pid pid;
DBG (2, "finish_pass: terminating reader process %ld\n", DBG (2, "finish_pass: terminating reader process %ld\n",
(long) test_device->reader_pid); sanei_thread_pid_to_long(test_device->reader_pid));
sanei_thread_kill (test_device->reader_pid); sanei_thread_kill (test_device->reader_pid);
pid = sanei_thread_waitpid (test_device->reader_pid, &status); pid = sanei_thread_waitpid (test_device->reader_pid, &status);
if (!sanei_thread_is_valid (pid)) if (!sanei_thread_is_valid (pid))

Wyświetl plik

@ -409,7 +409,7 @@ static SANE_Status do_cancel( U12_Scanner *scanner, SANE_Bool closepipe )
res = sanei_thread_waitpid( scanner->reader_pid, 0 ); res = sanei_thread_waitpid( scanner->reader_pid, 0 );
alarm(0); alarm(0);
if( res != scanner->reader_pid ) { if( !sanei_thread_pid_compare(res, scanner->reader_pid) ) {
DBG( _DBG_PROC,"sanei_thread_waitpid() failed !\n"); DBG( _DBG_PROC,"sanei_thread_waitpid() failed !\n");
/* do it the hard way...*/ /* do it the hard way...*/

Wyświetl plik

@ -62,11 +62,40 @@
#ifdef USE_PTHREAD #ifdef USE_PTHREAD
#include <pthread.h> #include <pthread.h>
typedef pthread_t SANE_Pid;
#else
typedef int SANE_Pid;
#endif #endif
/** Object used to identify a thread or process.
*
* SANE_Pid is defined with an additional validity flag
* since there is no cross-platform consensus on how to construct
* a pthread_t that can be reliably tested for validity.
* This is because pthread_t is opaque so we *cannot* make assumptions
* about what the underlying type is. It is often an int, sometimes
* a pointer and rarely an actual structure.
*
* Comparing pthread_t values for equality with == is not defined!
* Using pthread_equal() for pthread_t is recommended.
* For users of this API, we will provide a function sanei_thread_pid_compare()
* for comparing SANE_Pids and callers are urged to use it.
*
* In any case, comparing two pids with the same pthread_t will fail
* equality tests if either of the pids are marked as invalid.
* Two invalid pids are not equal.
*
*/
typedef struct
{
SANE_Bool is_valid;
#ifdef USE_PTHREAD
pthread_t pid;
#else
int pid;
#endif
} SANE_Pid;
/** Initialize sanei_thread. /** Initialize sanei_thread.
* *
* This function must be called before any other sanei_thread function. * This function must be called before any other sanei_thread function.
@ -112,7 +141,7 @@ extern SANE_Bool sanei_thread_is_valid (SANE_Pid pid);
* For details on the pthread_t type, see in particular Issue 6 of * For details on the pthread_t type, see in particular Issue 6 of
* http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/sys_types.h.html * http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/sys_types.h.html
*/ */
#define sanei_thread_invalidate(pid) ((pid) = (SANE_Pid)(-1)) #define sanei_thread_invalidate(sane_pid) ((sane_pid).is_valid = SANE_FALSE)
/** Initialize a SANE_Pid /** Initialize a SANE_Pid
* *
@ -194,4 +223,31 @@ extern SANE_Pid sanei_thread_waitpid (SANE_Pid pid, int *status);
*/ */
extern SANE_Status sanei_thread_get_status (SANE_Pid pid); extern SANE_Status sanei_thread_get_status (SANE_Pid pid);
/** Compare SANE_Pid for equality.
*
* @param pid1 - the id of the first task
* @param pid2 - the id of the second task
*
* @return
* - SANE_TRUE - if the SANE_Pids are the same (or equivalent).
* - SANE_FALSE - if the SANE_Pids are not the same (or not equivalent).
*/
extern SANE_Bool sanei_thread_pid_compare (SANE_Pid pid1, SANE_Pid pid2);
/** Generate a long value to represent a SANE_Pid
*
* We cannot make any assumptions about what this long value represents since
* the underlying thread/process id on each platform may be different.
*
* It is handy for display purposes though, for example identifying which thread
* is being referred to in diagnostics.
*
* @param pid - the id of the task
*
* @return
* - long value of pid.
*/
extern long sanei_thread_pid_to_long( SANE_Pid pid );
#endif /* sanei_thread_h */ #endif /* sanei_thread_h */

Wyświetl plik

@ -117,16 +117,7 @@ sanei_thread_is_forked( void )
static void static void
sanei_thread_set_invalid( SANE_Pid *pid ) sanei_thread_set_invalid( SANE_Pid *pid )
{ {
sanei_thread_invalidate(*pid);
#ifdef WIN32
#ifdef WINPTHREAD_API
*pid = (pthread_t) 0;
#else
pid->p = 0;
#endif
#else
*pid = (pthread_t) -1;
#endif
} }
#endif #endif
@ -134,40 +125,34 @@ sanei_thread_set_invalid( SANE_Pid *pid )
SANE_Bool SANE_Bool
sanei_thread_is_valid( SANE_Pid pid ) sanei_thread_is_valid( SANE_Pid pid )
{ {
SANE_Bool rc = SANE_TRUE; return pid.is_valid;
#ifdef WIN32
#ifdef WINPTHREAD_API
if (pid == 0)
#else
if (pid.p == 0)
#endif
rc = SANE_FALSE;
#else
if (pid == (SANE_Pid) -1)
rc = SANE_FALSE;
#endif
return rc;
} }
/* pthread_t is not an integer on all platform. Do our best to return /* pthread_t is not an integer on all platform. Do our best to return
* a PID-like value from structure. On platforms were it is an integer, * a PID-like value from structure. On platforms were it is an integer,
* return that. * return that.
*
* Note: perhaps on platforms where pthread_t is a structure, compute a hash
* of the structure. It's not ideal but it is a thought.
*
*/ */
static long long
sanei_thread_pid_to_long( SANE_Pid pid ) sanei_thread_pid_to_long( SANE_Pid pid )
{ {
int rc; int rc;
if (!pid.is_valid)
{
return 0l;
}
#ifdef WIN32 #ifdef WIN32
#ifdef WINPTHREAD_API #ifdef WINPTHREAD_API
rc = (long) pid; rc = (long) pid.pid;
#else #else
rc = pid.p; rc = pid.pid.p;
#endif #endif
#else #else
rc = (long) pid; rc = (long) pid.pid;
#endif #endif
return rc; return rc;
@ -176,18 +161,22 @@ sanei_thread_pid_to_long( SANE_Pid pid )
int int
sanei_thread_kill( SANE_Pid pid ) sanei_thread_kill( SANE_Pid pid )
{ {
if (!pid.is_valid)
{
return -1;
}
DBG(2, "sanei_thread_kill() will kill %ld\n", DBG(2, "sanei_thread_kill() will kill %ld\n",
sanei_thread_pid_to_long(pid)); sanei_thread_pid_to_long(pid));
#ifdef USE_PTHREAD #ifdef USE_PTHREAD
#if defined (__APPLE__) && defined (__MACH__) #if defined (__APPLE__) && defined (__MACH__)
return pthread_kill((pthread_t)pid, SIGUSR2); return pthread_kill((pthread_t)pid.pid, SIGUSR2);
#else #else
return pthread_cancel((pthread_t)pid); return pthread_cancel((pthread_t)pid.pid);
#endif #endif
#elif defined HAVE_OS2_H #elif defined HAVE_OS2_H
return DosKillThread(pid); return DosKillThread(pid.pid);
#else #else
return kill( pid, SIGTERM ); return kill( pid.pid, SIGTERM );
#endif #endif
} }
@ -208,31 +197,40 @@ local_thread( void *arg )
/* /*
* starts a new thread or process * starts a new thread or process
* parameters: * parameters:
* star address of reader function *
* func address of reader function
* args pointer to scanner data structure * args pointer to scanner data structure
* *
*/ */
SANE_Pid SANE_Pid
sanei_thread_begin( int (*func)(void *args), void* args ) sanei_thread_begin( int (*func)(void *args), void* args )
{ {
SANE_Pid pid; SANE_Pid pid = {SANE_FALSE, -1};
td.func = func; td.func = func;
td.func_data = args; td.func_data = args;
pid = _beginthread( local_thread, NULL, 1024*1024, (void*)&td ); pid.pid = _beginthread( local_thread, NULL, 1024*1024, (void*)&td );
if ( pid == -1 ) { if ( pid.pid == -1 )
{
DBG( 1, "_beginthread() failed\n" ); DBG( 1, "_beginthread() failed\n" );
return -1; return pid;
} }
DBG( 2, "_beginthread() created thread %d\n", pid ); DBG( 2, "_beginthread() created thread %d\n", pid );
pid.is_valid = SANE_TRUE;
return pid; return pid;
} }
SANE_Pid SANE_Pid
sanei_thread_waitpid( SANE_Pid pid, int *status ) sanei_thread_waitpid( SANE_Pid pid, int *status )
{ {
if (!pid.is_valid)
{
return pid;
}
if (status) if (status)
*status = 0; *status = 0;
return pid; /* DosWaitThread( (TID*) &pid, DCWW_WAIT);*/ return pid; /* DosWaitThread( (TID*) &pid, DCWW_WAIT);*/
@ -241,6 +239,10 @@ sanei_thread_waitpid( SANE_Pid pid, int *status )
int int
sanei_thread_sendsig( SANE_Pid pid, int sig ) sanei_thread_sendsig( SANE_Pid pid, int sig )
{ {
if (!pid.is_valid)
{
return -1;
}
return 0; return 0;
} }
@ -268,22 +270,24 @@ local_thread( void *arg )
SANE_Pid SANE_Pid
sanei_thread_begin( int (*func)(void *args), void* args ) sanei_thread_begin( int (*func)(void *args), void* args )
{ {
SANE_Pid pid; SANE_Pid pid = {SANE_FALSE, B_OK};
td.func = func; td.func = func;
td.func_data = args; td.func_data = args;
pid = spawn_thread( local_thread, "sane thread (yes they can be)", B_NORMAL_PRIORITY, (void*)&td ); pid.pid = spawn_thread( local_thread, "sane thread (yes they can be)", B_NORMAL_PRIORITY, (void*)&td );
if ( pid < B_OK ) { if ( pid.pid < B_OK ) {
DBG( 1, "spawn_thread() failed\n" ); DBG( 1, "spawn_thread() failed\n" );
return -1; return pid;
} }
if ( resume_thread(pid) < B_OK ) { if ( resume_thread(pid.pid) < B_OK ) {
DBG( 1, "resume_thread() failed\n" ); DBG( 1, "resume_thread() failed\n" );
return -1; return pid;
} }
DBG( 2, "spawn_thread() created thread %d\n", pid ); DBG( 2, "spawn_thread() created thread %d\n", pid );
pid.is_valid = SANE_TRUE;
return pid; return pid;
} }
@ -291,19 +295,35 @@ SANE_Pid
sanei_thread_waitpid( SANE_Pid pid, int *status ) sanei_thread_waitpid( SANE_Pid pid, int *status )
{ {
int32 st; int32 st;
if ( wait_for_thread(pid, &st) < B_OK )
return -1; if (!pid.is_valid)
{
return pid;
}
if ( wait_for_thread(pid.pid, &st) < B_OK )
{
pid.is_valid = SANE_FALSE;
return pid;
}
if ( status ) if ( status )
*status = (int)st; *status = (int)st;
return pid; return pid;
} }
int int
sanei_thread_sendsig( SANE_Pid pid, int sig ) sanei_thread_sendsig( SANE_Pid pid, int sig )
{ {
if (!pid.is_valid)
{
return -1;
}
if (sig == SIGKILL) if (sig == SIGKILL)
sig = SIGKILLTHR; sig = SIGKILLTHR;
return kill(pid, sig);
return kill(pid.pid, sig);
} }
#else /* HAVE_OS2_H, __BEOS__ */ #else /* HAVE_OS2_H, __BEOS__ */
@ -388,7 +408,7 @@ eval_wp_result( SANE_Pid pid, int wpres, int pf )
{ {
int retval = SANE_STATUS_IO_ERROR; int retval = SANE_STATUS_IO_ERROR;
if( wpres == pid ) { if( wpres == pid.pid ) {
if( WIFEXITED(pf)) { if( WIFEXITED(pf)) {
retval = WEXITSTATUS(pf); retval = WEXITSTATUS(pf);
@ -412,7 +432,8 @@ sanei_thread_begin( int (func)(void *args), void* args )
{ {
#ifdef USE_PTHREAD #ifdef USE_PTHREAD
int result; int result;
pthread_t thread; SANE_Pid thread;
#ifdef SIGPIPE #ifdef SIGPIPE
struct sigaction act; struct sigaction act;
@ -433,27 +454,38 @@ sanei_thread_begin( int (func)(void *args), void* args )
td.func = func; td.func = func;
td.func_data = args; td.func_data = args;
result = pthread_create( &thread, NULL, local_thread, &td ); result = pthread_create( &thread.pid, NULL, local_thread, &td );
usleep( 1 ); usleep( 1 );
if ( result != 0 ) { if ( result != 0 )
{
DBG( 1, "pthread_create() failed with %d\n", result ); DBG( 1, "pthread_create() failed with %d\n", result );
sanei_thread_set_invalid(&thread); sanei_thread_set_invalid(&thread);
} }
else else
{
DBG( 2, "pthread_create() created thread %ld\n", DBG( 2, "pthread_create() created thread %ld\n",
sanei_thread_pid_to_long(thread) ); sanei_thread_pid_to_long(thread) );
thread.is_valid = SANE_TRUE;
return (SANE_Pid)thread;
#else
SANE_Pid pid;
pid = fork();
if( pid < 0 ) {
DBG( 1, "fork() failed\n" );
return -1;
} }
if( pid == 0 ) { return thread;
#else
SANE_Pid pid = {SANE_FALSE, 0};
pid.pid = fork();
if( pid.pid < 0 )
{
DBG( 1, "fork() failed\n" );
return pid;
}
pid.is_valid = SANE_TRUE;
/*
* If I am the child....
*
*/
if( pid.pid == 0 ) {
/* run in child context... */ /* run in child context... */
int status = func( args ); int status = func( args );
@ -472,10 +504,15 @@ sanei_thread_sendsig( SANE_Pid pid, int sig )
{ {
DBG(2, "sanei_thread_sendsig() %d to thread (id=%ld)\n", sig, DBG(2, "sanei_thread_sendsig() %d to thread (id=%ld)\n", sig,
sanei_thread_pid_to_long(pid)); sanei_thread_pid_to_long(pid));
if (!pid.is_valid)
{
return -1;
}
#ifdef USE_PTHREAD #ifdef USE_PTHREAD
return pthread_kill( (pthread_t)pid, sig ); return pthread_kill( (pthread_t)pid.pid, sig );
#else #else
return kill( pid, sig ); return kill( pid.pid, sig );
#endif #endif
} }
@ -490,32 +527,55 @@ sanei_thread_waitpid( SANE_Pid pid, int *status )
SANE_Pid result = pid; SANE_Pid result = pid;
int stat; int stat;
/*
* Can't join if the PID is invalid.
*
* Normally, we would assume that the below call would fail if
* the provided pid was invalid. However, we are now using a separate
* boolean flag in SANE_Pid so we must check this.
*
* We must assume that the caller is making rational assumptions when
* using SANE_Pid. You cannot assume that SANE_Pid is a pthread_t in
* particular.
*
*/
if (!pid.is_valid)
{
DBG(1, "sanei_thread_waitpid() - provided pid is invalid!\n");
return pid;
}
stat = 0; stat = 0;
DBG(2, "sanei_thread_waitpid() - %ld\n", DBG(2, "sanei_thread_waitpid() - %ld\n", sanei_thread_pid_to_long(pid));
sanei_thread_pid_to_long(pid));
#ifdef USE_PTHREAD #ifdef USE_PTHREAD
int rc; int rc;
rc = pthread_join( (pthread_t)pid, (void*)&ls ); rc = pthread_join( pid.pid, (void*)&ls );
if( 0 == rc ) { if( 0 == rc )
if( PTHREAD_CANCELED == ls ) { {
if( PTHREAD_CANCELED == ls )
{
DBG(2, "* thread has been canceled!\n" ); DBG(2, "* thread has been canceled!\n" );
stat = SANE_STATUS_GOOD; stat = SANE_STATUS_GOOD;
} else { }
else
{
stat = *ls; stat = *ls;
} }
DBG(2, "* result = %d (%p)\n", stat, (void*)status ); DBG(2, "* result = %d (%p)\n", stat, (void*)status );
result = pid; result = pid;
} }
if ( EDEADLK == rc ) { if ( EDEADLK == rc )
if ( (pthread_t)pid != pthread_self() ) { {
if (!pthread_equal(pid.pid, pthread_self()))
{
/* call detach in any case to make sure that the thread resources /* call detach in any case to make sure that the thread resources
* will be freed, when the thread has terminated * will be freed, when the thread has terminated
*/ */
DBG(2, "* detaching thread(%ld)\n", DBG(2, "* detaching thread(%ld)\n",
sanei_thread_pid_to_long(pid) ); sanei_thread_pid_to_long(pid) );
pthread_detach((pthread_t)pid); pthread_detach(pid.pid);
} }
} }
if (status) if (status)
@ -523,7 +583,7 @@ sanei_thread_waitpid( SANE_Pid pid, int *status )
restore_sigpipe(); restore_sigpipe();
#else #else
result = waitpid( pid, &ls, 0 ); result = waitpid( pid.pid, &ls, 0 );
if((result < 0) && (errno == ECHILD)) { if((result < 0) && (errno == ECHILD)) {
stat = SANE_STATUS_GOOD; stat = SANE_STATUS_GOOD;
result = pid; result = pid;
@ -550,9 +610,9 @@ sanei_thread_get_status( SANE_Pid pid )
int ls, stat, result; int ls, stat, result;
stat = SANE_STATUS_IO_ERROR; stat = SANE_STATUS_IO_ERROR;
if( pid > 0 ) { if (pid.is_valid && (pid.pid > 0) )
{
result = waitpid( pid, &ls, WNOHANG ); result = waitpid( pid.pid, &ls, WNOHANG );
stat = eval_wp_result( pid, result, ls ); stat = eval_wp_result( pid, result, ls );
} }
@ -560,4 +620,26 @@ sanei_thread_get_status( SANE_Pid pid )
#endif #endif
} }
/*
* Note: for the case of where the underlying system pid is neither
* a pointer nor an integer, we should use an appropriate platform function
* for comparing pids. We will have to take each case as it comes.
*
*/
SANE_Bool
sanei_thread_pid_compare (SANE_Pid pid1, SANE_Pid pid2)
{
if (!pid1.is_valid || !pid2.is_valid)
{
return SANE_FALSE;
}
#if defined USE_PTHREAD
return pthread_equal(pid1.pid, pid2.pid)? SANE_TRUE: SANE_FALSE;
#else
return pid1.pid == pid2.pid;
#endif
}
/* END sanei_thread.c .......................................................*/ /* END sanei_thread.c .......................................................*/