sanei_thread: Draft fixup for sanei_thread issues.

sanei_thread_fixup
Ralph Little 2022-08-28 16:54:48 -07:00
rodzic 9330bfdd83
commit 0b009ce12d
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);
alarm (0);
if (res != s->reader_pid)
if (!sanei_thread_pid_compare(res, s->reader_pid))
{
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: */
sanei_thread_kill (scanner->reader_pid);
while (sanei_thread_waitpid(scanner->reader_pid, &exit_status) !=
scanner->reader_pid );
while (!sanei_thread_pid_compare(sanei_thread_waitpid(scanner->reader_pid, &exit_status),
scanner->reader_pid) )
;
sanei_thread_invalidate (scanner->reader_pid);
}

Wyświetl plik

@ -90,7 +90,7 @@ struct hp_handle_s
static hp_bool_t
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];
sigset_t old_set;
assert(this->reader_pid == 0);
assert(!sanei_thread_is_valid(this->reader_pid));
this->cancelled = 0;
this->pipe_write_fd = this->pipe_read_fd = -1;
@ -178,39 +178,38 @@ hp_handle_startReader (HpHandle this, HpScsi scsi)
/* Returning means to be in the parent or thread/fork failed */
this->reader_pid = sanei_thread_begin (this->child_forked ? reader_process :
reader_thread, (void *) this);
if (this->reader_pid != 0)
if (sanei_thread_is_valid (this->reader_pid))
{
/* Here we are in the parent */
sigprocmask(SIG_SETMASK, &old_set, 0);
if ( this->child_forked )
{ /* After fork(), parent must close writing end of pipe */
DBG(3, "hp_handle_startReader: parent closes write end of pipe\n");
close (this->pipe_write_fd);
this->pipe_write_fd = -1;
}
if (this->child_forked)
{ /* After fork(), parent must close writing end of pipe */
DBG (3, "hp_handle_startReader: parent closes write end of pipe\n");
close (this->pipe_write_fd);
this->pipe_write_fd = -1;
}
if (!sanei_thread_is_valid (this->reader_pid))
{
if ( !this->child_forked )
{
close (this->pipe_write_fd);
this->pipe_write_fd = -1;
}
close (this->pipe_read_fd);
this->pipe_read_fd = -1;
DBG(1, "hp_handle_startReader: fork() failed\n");
return SANE_STATUS_IO_ERROR;
}
DBG(1, "start_reader: reader process %ld started\n", (long) this->reader_pid);
DBG (1, "start_reader: reader process %ld started\n",
sanei_thread_pid_to_long (this->reader_pid));
return SANE_STATUS_GOOD;
}
DBG(3, "Unexpected return from sanei_thread_begin()\n");
return SANE_STATUS_INVAL;
/*
* Error kicking off the reader.
*
*/
if (!this->child_forked)
{
close (this->pipe_write_fd);
this->pipe_write_fd = -1;
}
close (this->pipe_read_fd);
this->pipe_read_fd = -1;
DBG (1, "hp_handle_startReader: fork()/thread start failed\n");
return SANE_STATUS_IO_ERROR;
}
static SANE_Status
@ -221,10 +220,11 @@ hp_handle_stopScan (HpHandle this)
this->cancelled = 0;
this->bytes_left = 0;
if (this->reader_pid)
if (sanei_thread_is_valid(this->reader_pid))
{
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_waitpid(this->reader_pid, &info);
@ -232,7 +232,7 @@ hp_handle_stopScan (HpHandle this)
WIFEXITED(info) ? "exited, status" : "signalled, signal",
WIFEXITED(info) ? WEXITSTATUS(info) : WTERMSIG(info));
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)) )
{
@ -732,11 +732,11 @@ sanei_hp_handle_cancel (HpHandle this)
/* Therefore the read might not return until it is interrupted. */
DBG(3,"sanei_hp_handle_cancel: compat flags: 0x%04x\n",
(int)this->dev->compat);
if ( (this->reader_pid)
&& (this->dev->compat & HP_COMPAT_OJ_1150C) )
if (sanei_thread_is_valid (this->reader_pid)
&& (this->dev->compat & HP_COMPAT_OJ_1150C))
{
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);
}
}

Wyświetl plik

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

Wyświetl plik

@ -1228,7 +1228,7 @@ terminate_reader_task (pixma_sane_t * ss, int *exit_code)
if (ss->sp.source != PIXMA_SOURCE_ADF && ss->sp.source != PIXMA_SOURCE_ADFDUP)
ss->idle = SANE_TRUE;
if (result == pid)
if (sanei_thread_pid_compare(result, pid))
{
if (exit_code)
*exit_code = status;
@ -1261,7 +1261,8 @@ start_reader_task (pixma_sane_t * ss)
if (sanei_thread_is_valid (ss->reader_taskid))
{
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);
}
if (pipe (fds) == -1)
@ -1297,7 +1298,8 @@ start_reader_task (pixma_sane_t * ss)
PDBG (pixma_dbg (1, "ERROR:unable to start reader task\n"));
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"));
ss->reader_taskid = pid;
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 );
alarm(0);
if( res != scanner->reader_pid ) {
if(!sanei_thread_pid_compare(res, scanner->reader_pid)) {
DBG( _DBG_PROC,"sanei_thread_waitpid() failed !\n");
/* 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 );
alarm(0);
if( res != scanner->reader_pid ) {
if( !sanei_thread_pid_compare(res, scanner->reader_pid) ) {
DBG( _DBG_PROC,"sanei_thread_waitpid() failed !\n");
/* 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 );
alarm(0);
if( res != pss->child ) {
if( !sanei_thread_pid_compare(res, pss->child) ) {
DBG( DL_MINOR_ERROR,"sanei_thread_waitpid() failed !\n");
/* do it the hard way...*/

Wyświetl plik

@ -1548,7 +1548,7 @@ finish_pass (Test_Device * test_device)
SANE_Pid pid;
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);
pid = sanei_thread_waitpid (test_device->reader_pid, &status);
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 );
alarm(0);
if( res != scanner->reader_pid ) {
if( !sanei_thread_pid_compare(res, scanner->reader_pid) ) {
DBG( _DBG_PROC,"sanei_thread_waitpid() failed !\n");
/* do it the hard way...*/

Wyświetl plik

@ -62,11 +62,40 @@
#ifdef USE_PTHREAD
#include <pthread.h>
typedef pthread_t SANE_Pid;
#else
typedef int SANE_Pid;
#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.
*
* 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
* 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).pid = SANE_FALSE)
/** 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);
/** 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 */

Wyświetl plik

@ -117,16 +117,7 @@ sanei_thread_is_forked( void )
static void
sanei_thread_set_invalid( SANE_Pid *pid )
{
#ifdef WIN32
#ifdef WINPTHREAD_API
*pid = (pthread_t) 0;
#else
pid->p = 0;
#endif
#else
*pid = (pthread_t) -1;
#endif
pid->pid = SANE_FALSE;
}
#endif
@ -134,40 +125,34 @@ sanei_thread_set_invalid( SANE_Pid *pid )
SANE_Bool
sanei_thread_is_valid( SANE_Pid pid )
{
SANE_Bool rc = SANE_TRUE;
#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;
return pid.is_valid;
}
/* 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,
* 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 )
{
int rc;
if (!pid.is_valid)
{
return 0l;
}
#ifdef WIN32
#ifdef WINPTHREAD_API
rc = (long) pid;
rc = (long) pid.pid;
#else
rc = pid.p;
rc = pid.pid.p;
#endif
#else
rc = (long) pid;
rc = (long) pid.pid;
#endif
return rc;
@ -176,18 +161,22 @@ sanei_thread_pid_to_long( SANE_Pid pid )
int
sanei_thread_kill( SANE_Pid pid )
{
if (!pid.is_valid)
{
return -1;
}
DBG(2, "sanei_thread_kill() will kill %ld\n",
sanei_thread_pid_to_long(pid));
#ifdef USE_PTHREAD
#if defined (__APPLE__) && defined (__MACH__)
return pthread_kill((pthread_t)pid, SIGUSR2);
return pthread_kill((pthread_t)pid.pid, SIGUSR2);
#else
return pthread_cancel((pthread_t)pid);
return pthread_cancel((pthread_t)pid.pid);
#endif
#elif defined HAVE_OS2_H
return DosKillThread(pid);
return DosKillThread(pid.pid);
#else
return kill( pid, SIGTERM );
return kill( pid.pid, SIGTERM );
#endif
}
@ -208,39 +197,52 @@ local_thread( void *arg )
/*
* starts a new thread or process
* parameters:
* star address of reader function
*
* func address of reader function
* args pointer to scanner data structure
*
*/
SANE_Pid
sanei_thread_begin( int (*func)(void *args), void* args )
{
SANE_Pid pid;
SANE_Pid pid = {SANE_FALSE, -1};
td.func = func;
td.func_data = args;
pid = _beginthread( local_thread, NULL, 1024*1024, (void*)&td );
if ( pid == -1 ) {
pid.pid = _beginthread( local_thread, NULL, 1024*1024, (void*)&td );
if ( pid.pid == -1 )
{
DBG( 1, "_beginthread() failed\n" );
return -1;
return pid;
}
DBG( 2, "_beginthread() created thread %d\n", pid );
pid.is_valid = SANE_TRUE;
return pid;
}
SANE_Pid
sanei_thread_waitpid( SANE_Pid pid, int *status )
{
if (status)
*status = 0;
return pid; /* DosWaitThread( (TID*) &pid, DCWW_WAIT);*/
if (!pid.is_valid)
{
return pid;
}
if (status)
*status = 0;
return pid; /* DosWaitThread( (TID*) &pid, DCWW_WAIT);*/
}
int
sanei_thread_sendsig( SANE_Pid pid, int sig )
{
if (!pid.is_valid)
{
return -1;
}
return 0;
}
@ -268,42 +270,60 @@ local_thread( void *arg )
SANE_Pid
sanei_thread_begin( int (*func)(void *args), void* args )
{
SANE_Pid pid;
SANE_Pid pid = {SANE_FALSE, B_OK};
td.func = func;
td.func_data = args;
pid = spawn_thread( local_thread, "sane thread (yes they can be)", B_NORMAL_PRIORITY, (void*)&td );
if ( pid < B_OK ) {
pid.pid = spawn_thread( local_thread, "sane thread (yes they can be)", B_NORMAL_PRIORITY, (void*)&td );
if ( pid.pid < B_OK ) {
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" );
return -1;
return pid;
}
DBG( 2, "spawn_thread() created thread %d\n", pid );
pid.is_valid = SANE_TRUE;
return pid;
}
SANE_Pid
sanei_thread_waitpid( SANE_Pid pid, int *status )
{
int32 st;
if ( wait_for_thread(pid, &st) < B_OK )
return -1;
if ( status )
*status = (int)st;
return pid;
int32 st;
if (!pid.is_valid)
{
return pid;
}
if ( wait_for_thread(pid.pid, &st) < B_OK )
{
pid.is_valid = SANE_FALSE;
return pid;
}
if ( status )
*status = (int)st;
return pid;
}
int
sanei_thread_sendsig( SANE_Pid pid, int sig )
{
if (!pid.is_valid)
{
return -1;
}
if (sig == SIGKILL)
sig = SIGKILLTHR;
return kill(pid, sig);
return kill(pid.pid, sig);
}
#else /* HAVE_OS2_H, __BEOS__ */
@ -389,7 +409,7 @@ eval_wp_result( SANE_Pid pid, int wpres, int pf )
{
int retval = SANE_STATUS_IO_ERROR;
if( wpres == pid ) {
if( wpres == pid.pid ) {
if( WIFEXITED(pf)) {
retval = WEXITSTATUS(pf);
@ -413,7 +433,8 @@ sanei_thread_begin( int (func)(void *args), void* args )
{
#ifdef USE_PTHREAD
int result;
pthread_t thread;
SANE_Pid thread;
#ifdef SIGPIPE
struct sigaction act;
@ -434,27 +455,38 @@ sanei_thread_begin( int (func)(void *args), void* args )
td.func = func;
td.func_data = args;
result = pthread_create( &thread, NULL, local_thread, &td );
result = pthread_create( &thread.pid, NULL, local_thread, &td );
usleep( 1 );
if ( result != 0 ) {
if ( result != 0 )
{
DBG( 1, "pthread_create() failed with %d\n", result );
sanei_thread_set_invalid(&thread);
}
else
{
DBG( 2, "pthread_create() created thread %ld\n",
sanei_thread_pid_to_long(thread) );
return (SANE_Pid)thread;
#else
SANE_Pid pid;
pid = fork();
if( pid < 0 ) {
DBG( 1, "fork() failed\n" );
return -1;
thread.is_valid = SANE_TRUE;
}
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... */
int status = func( args );
@ -473,10 +505,15 @@ sanei_thread_sendsig( SANE_Pid pid, int sig )
{
DBG(2, "sanei_thread_sendsig() %d to thread (id=%ld)\n", sig,
sanei_thread_pid_to_long(pid));
if (!pid.is_valid)
{
return -1;
}
#ifdef USE_PTHREAD
return pthread_kill( (pthread_t)pid, sig );
return pthread_kill( (pthread_t)pid.pid, sig );
#else
return kill( pid, sig );
return kill( pid.pid, sig );
#endif
}
@ -491,32 +528,55 @@ sanei_thread_waitpid( SANE_Pid pid, int *status )
SANE_Pid result = pid;
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;
DBG(2, "sanei_thread_waitpid() - %ld\n",
sanei_thread_pid_to_long(pid));
DBG(2, "sanei_thread_waitpid() - %ld\n", sanei_thread_pid_to_long(pid));
#ifdef USE_PTHREAD
int rc;
rc = pthread_join( (pthread_t)pid, (void*)&ls );
rc = pthread_join( pid.pid, (void*)&ls );
if( 0 == rc ) {
if( PTHREAD_CANCELED == ls ) {
if( 0 == rc )
{
if( PTHREAD_CANCELED == ls )
{
DBG(2, "* thread has been canceled!\n" );
stat = SANE_STATUS_GOOD;
} else {
}
else
{
stat = *ls;
}
DBG(2, "* result = %d (%p)\n", stat, (void*)status );
result = pid;
}
if ( EDEADLK == rc ) {
if ( (pthread_t)pid != pthread_self() ) {
if ( EDEADLK == rc )
{
if (!pthread_equal(pid.pid, pthread_self()))
{
/* call detach in any case to make sure that the thread resources
* will be freed, when the thread has terminated
*/
DBG(2, "* detaching thread(%ld)\n",
sanei_thread_pid_to_long(pid) );
pthread_detach((pthread_t)pid);
pthread_detach(pid.pid);
}
}
if (status)
@ -524,7 +584,7 @@ sanei_thread_waitpid( SANE_Pid pid, int *status )
restore_sigpipe();
#else
result = waitpid( pid, &ls, 0 );
result = waitpid( pid.pid, &ls, 0 );
if((result < 0) && (errno == ECHILD)) {
stat = SANE_STATUS_GOOD;
result = pid;
@ -551,9 +611,9 @@ sanei_thread_get_status( SANE_Pid pid )
int ls, stat, result;
stat = SANE_STATUS_IO_ERROR;
if( pid > 0 ) {
result = waitpid( pid, &ls, WNOHANG );
if (pid.is_valid && (pid.pid > 0) )
{
result = waitpid( pid.pid, &ls, WNOHANG );
stat = eval_wp_result( pid, result, ls );
}
@ -561,4 +621,26 @@ sanei_thread_get_status( SANE_Pid pid )
#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 .......................................................*/