From 18c43a087deef305c026316be60eef2a8398ffe4 Mon Sep 17 00:00:00 2001 From: Julien BLACHE Date: Sat, 11 Dec 2004 08:20:52 +0000 Subject: [PATCH] sanei resync with sane-backends, fixes a deadlock between xscanimage and saned when scanning over the network. --- Changelog | 4 + include/sane/sanei.h | 139 ++++++++++- include/sane/sanei_codec_ascii.h | 40 +++- include/sane/sanei_codec_bin.h | 39 +++- include/sane/sanei_debug.h | 117 ++++++++-- include/sane/sanei_wire.h | 28 +++ sanei/sanei_codec_bin.c | 15 +- sanei/sanei_thread.c | 383 ++++++++++++++++++++++++++++--- sanei/sanei_wire.c | 370 +++++++++++++++++++++++------ 9 files changed, 1002 insertions(+), 133 deletions(-) diff --git a/Changelog b/Changelog index 2d12ad9..f840303 100644 --- a/Changelog +++ b/Changelog @@ -1,3 +1,7 @@ +2004-12-11 Julien Blache + * sanei resync with sane-backends, fixes a deadlock between xscanimage + and saned when scanning over the network. + 2004-10-30 Henning Meier-Geinitz * doc/scanadf.man src/scanadf.c: Wait for scan-scripts so all diff --git a/include/sane/sanei.h b/include/sane/sanei.h index 93f75dd..d736b17 100644 --- a/include/sane/sanei.h +++ b/include/sane/sanei.h @@ -1,5 +1,7 @@ /* sane - Scanner Access Now Easy. Copyright (C) 1996 David Mosberger-Tang and Andreas Beck + Copyright (C) 2002, 2003 Henning Meier-Geinitz + This file is part of the SANE package. SANE is free software; you can redistribute it and/or modify it @@ -16,26 +18,155 @@ along with sane; see the file COPYING. If not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - This file declares SANE internal routines that are provided to - simplify backend implementation. */ + As a special exception, the authors of SANE give permission for + additional uses of the libraries contained in this release of SANE. + + The exception is that, if you link a SANE library with other files + to produce an executable, this does not by itself cause the + resulting executable to be covered by the GNU General Public + License. Your use of that executable is in no way restricted on + account of linking the SANE library code into it. + + This exception does not, however, invalidate any other reasons why + the executable file might be covered by the GNU General Public + License. + + If you submit changes to SANE to the maintainers to be included in + a subsequent release, you agree by submitting the changes that + those changes may be distributed with this exception intact. + + If you write modifications of your own for SANE, it is your choice + whether to permit this exception to apply to your modifications. + If you do not wish that, delete this exception notice. +*/ + +/** @file sanei.h + * Convenience macros and function declarations for backends + * @sa sanei_backend.h sanei_thread.h + */ + +/* Doxygen documentation */ + +/** @mainpage SANEI (SANE internal routines) documentation + * + * @image html ../images/sane-logo2.jpg + * @section intro Introduction + * + * The header files in the include/sane/ directory named sanei_*.h provide + * function declarations and macros that can be used by every SANE backend. + * Their implementations can be found in the sanei/ directory. The code aims + * to be platform-independent to avoid lots of \#ifdef code in the backends. + * Please use the SANEI functions wherever possible. + * + * This documentation was created by the use of doxygen, the + * doc/doxygen-sanei.conf configuration file and dcoumentation in the sanei_*.h + * files. + * + * This documenation is far from complete. Any help is appreciated. + * + * @section additional Additional documentation + * - The SANE standard can be found at the SANE webserver. + * - Information on how to write a backend: backend-writing.txt. + * - General SANE documentation is on mailing list webpage + * for details. That's the place to ask questions, report bugs, or announce + * a new backend. + * + */ #ifndef sanei_h #define sanei_h #include -/* A few convenience macros: */ +/** @name Public macros and functions + * @{ + */ +/** @def STRINGIFY(x) + * Turn parameter into string. + */ +/** @def PASTE(x,y) + * Concatenate parameters. + * + */ +/** @def NELEMS(a) + * Return number of elements of an array. + * + */ +/** @fn extern SANE_Status sanei_check_value (const SANE_Option_Descriptor * opt, void * value); + * Check the constraints of a SANE option. + * + * @param opt option to check + * @param value value of the option + * + * @return + * - SANE_STATUS_GOOD - on success + * - SANE_STATUS_INVAL - if the value doesn't fit inside the constraint + * or any other error occured + * @sa sanei_constrain_value() + */ + +/** @fn extern SANE_Status sanei_constrain_value (const SANE_Option_Descriptor * opt, void * value, SANE_Word * info); + * Check the constraints of a SANE option and adjust its value if necessary. + * + * Depending on the type of the option and constraint, value is modified + * to fit inside constraint. + * + * @param opt option to check + * @param value value of the option + * @param info info is set to SANE_INFO_INEXACT if value was changed + * + * @return + * - SANE_STATUS_GOOD - on success + * - SANE_STATUS_INVAL - if the function wasn't able to fit value into the + * constraint or any other error occured + * @sa sanei_check_value() + */ + +/* @} */ + +/** @name Private macros + * @{ + */ +/** @def STRINGIFY1(x) + * Internal use only. + */ +/** @def PASTE1(x,y) + * Internal use only. + */ +/* @} */ + +/* A few convenience macros: */ +/** @hideinitializer */ +#define NELEMS(a) ((int)(sizeof (a) / sizeof (a[0]))) + +/** @hideinitializer */ #define STRINGIFY1(x) #x +/** @hideinitializer */ #define STRINGIFY(x) STRINGIFY1(x) +/** @hideinitializer */ #define PASTE1(x,y) x##y +/** @hideinitializer */ #define PASTE(x,y) PASTE1(x,y) -#define NELEMS(a) ((int)(sizeof (a) / sizeof (a[0]))) +extern SANE_Status sanei_check_value (const SANE_Option_Descriptor * opt, + void * value); extern SANE_Status sanei_constrain_value (const SANE_Option_Descriptor * opt, void * value, SANE_Word * info); + + extern int sanei_save_values (int fd, SANE_Handle device); extern int sanei_load_values (int fd, SANE_Handle device); diff --git a/include/sane/sanei_codec_ascii.h b/include/sane/sanei_codec_ascii.h index 1eb3a2a..991499a 100644 --- a/include/sane/sanei_codec_ascii.h +++ b/include/sane/sanei_codec_ascii.h @@ -16,11 +16,47 @@ along with sane; see the file COPYING. If not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - This file declares SANE application interface. See the SANE - standard for a detailed explanation of the interface. */ + As a special exception, the authors of SANE give permission for + additional uses of the libraries contained in this release of SANE. + + The exception is that, if you link a SANE library with other files + to produce an executable, this does not by itself cause the + resulting executable to be covered by the GNU General Public + License. Your use of that executable is in no way restricted on + account of linking the SANE library code into it. + + This exception does not, however, invalidate any other reasons why + the executable file might be covered by the GNU General Public + License. + + If you submit changes to SANE to the maintainers to be included in + a subsequent release, you agree by submitting the changes that + those changes may be distributed with this exception intact. + + If you write modifications of your own for SANE, it is your choice + whether to permit this exception to apply to your modifications. + If you do not wish that, delete this exception notice. +*/ + +/** @file sanei_codec_ascii.h + * ASCII codec for network and file transmissions + * + * Instead translating data to a byte stream this codec uses ASCII hex numbers. + * Therefore it can be used for streams that are not 8-bit clean or which can + * only use printable characters. It's currently used for saving/restoring + * data to/from disk. + * + * @sa sanei_codec_bin.h sanei_net.h sanei_wire.h + */ #ifndef sanei_codec_ascii_h #define sanei_codec_ascii_h +/** Initialize the ascii codec + * + * Set the i/o functions of the Wire to those of the ASCII codec. + * + * @param w Wire + */ extern void sanei_codec_ascii_init (Wire *w); #endif /* sanei_codec_ascii_h */ diff --git a/include/sane/sanei_codec_bin.h b/include/sane/sanei_codec_bin.h index 120a20f..ba17bac 100644 --- a/include/sane/sanei_codec_bin.h +++ b/include/sane/sanei_codec_bin.h @@ -16,11 +16,46 @@ along with sane; see the file COPYING. If not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - This file declares SANE application interface. See the SANE - standard for a detailed explanation of the interface. */ + As a special exception, the authors of SANE give permission for + additional uses of the libraries contained in this release of SANE. + + The exception is that, if you link a SANE library with other files + to produce an executable, this does not by itself cause the + resulting executable to be covered by the GNU General Public + License. Your use of that executable is in no way restricted on + account of linking the SANE library code into it. + + This exception does not, however, invalidate any other reasons why + the executable file might be covered by the GNU General Public + License. + + If you submit changes to SANE to the maintainers to be included in + a subsequent release, you agree by submitting the changes that + those changes may be distributed with this exception intact. + + If you write modifications of your own for SANE, it is your choice + whether to permit this exception to apply to your modifications. + If you do not wish that, delete this exception notice. +*/ + +/** @file sanei_codec_bin.h + * Binary codec for network transmissions + * + * Transtale data to a byte stream while taking byte order problems into + * account. This codec is currently used for saned and the network backend. + * + * @sa sanei_codec_ascii.h sanei_net.h sanei_wire.h + */ + #ifndef sanei_codec_bin_h #define sanei_codec_bin_h +/** Initialize the binary codec + * + * Set the i/o functions of the Wire to those of the binary codec. + * + * @param w Wire + */ extern void sanei_codec_bin_init (Wire *w); #endif /* sanei_codec_bin_h */ diff --git a/include/sane/sanei_debug.h b/include/sane/sanei_debug.h index 7888a7c..5cf2e45 100644 --- a/include/sane/sanei_debug.h +++ b/include/sane/sanei_debug.h @@ -1,28 +1,95 @@ +/** @file sanei_debug.h + * Support for printing debug messages. + * + * Use the functions of this header file to print debug or warning messages. + */ + #ifndef _SANEI_DEBUG_H #define _SANEI_DEBUG_H #include -/* this header file defines: +/** @name Public macros + * These macros can be used in backends and other SANE-related + * code. * - * DBG_INIT() - should be called before any other debug function - * DBG(level, fmt, ...) - prints a message at debug level `level' or higher - * using a printf-like function - * IF_DBG(x) - expands to x if debug support is enabled at - * compile-time, if NDEBUG is defined at compile-time - * this macro expands to nothing + * Before including sanei_debug.h, the following macros must be set: * - * ENTRY(name) - expands to sane_BACKEND_NAME_name - * - * before you include sanei_debug.h, you'll have to define - * - * BACKEND_NAME - the name of your backend without double-quotes - * STUBS - if this is defined, nothing will happen - * DEBUG_DECLARE_ONLY - generate prototypes instead of functions - * DEBUG_NOT_STATIC - doesn't generate static functions + * - BACKEND_NAME - The name of your backend without double-quotes (must be set in any case) + * - STUBS - If this is defined, no macros will be included. Used in + * backends consisting of more than one .c file. + * - DEBUG_DECLARE_ONLY - Generates prototypes instead of functions. Used in + * backends consisting of more than one .c file. + * - DEBUG_NOT_STATIC - Doesn't generate static functions. Used in header files if + * they are include in more than one .c file. * + * @{ */ +/** @def DBG_INIT() + * Initialize sanei_debug. + * + * Call this function before you use any DBG function. + */ + +/** @def DBG(level, fmt, ...) + * Print a message at debug level `level' or higher using a printf-like + * function. Example: DBG(1, "sane_open: opening fd \%d\\n", fd). + * + * @param level debug level + * @param fmt format (see man 3 printf for details) + * @param ... additional arguments + */ + +/** @def IF_DBG(x) + * Compile code only if debugging is enabled. + * + * Expands to x if debug support is enabled at compile-time. If NDEBUG is + * defined at compile-time this macro expands to nothing. + * + * @param x code to expand when debugging is enabled + */ + +/** + * @def DBG_LEVEL + * Current debug level. + * + * You can only read this "variable". + */ + +/** @def ENTRY(name) + * Expands to sane_BACKEND_NAME_name. + * + * Example: ENTRY(init) in mustek.c will expand to sane_mustek_init. + */ + +/* @} */ + +/** @name Internal macros and functions + * Do not use in your own code. + * @{ + */ + +/** @def DBG_LOCAL + * Do not use in backends directly. + * + * Internal wrapper for printing function. + */ + +/** @fn extern void sanei_init_debug (const char * backend, int * debug_level_var); + * Do not use in backends directly. + * + * Actual init function. + */ + +/** @fn extern void sanei_debug_msg (int level, int max_level, const char *be, const char *fmt, va_list ap); + * Do not use in backends directly. + * + * Actual printing function. + */ +/* @} */ + + /** @hideinitializer*/ #define ENTRY(name) PASTE(PASTE(PASTE(sane_,BACKEND_NAME),_),name) #ifdef NDEBUG @@ -36,6 +103,7 @@ extern void sanei_debug_ndebug (int level, const char *msg, ...); #else /* !NDEBUG */ + /** @hideinitializer*/ # define DBG_LEVEL PASTE(sanei_debug_,BACKEND_NAME) # if defined(BACKEND_NAME) && !defined(STUBS) @@ -46,9 +114,11 @@ int DBG_LEVEL = 0; # endif /* DEBUG_DECLARE_ONLY */ # endif /* BACKEND_NAME && !STUBS */ + /** @hideinitializer*/ # define DBG_INIT() \ sanei_init_debug (STRINGIFY(BACKEND_NAME), &DBG_LEVEL) + /** @hideinitializer*/ # define DBG_LOCAL PASTE(DBG_LEVEL,_call) @@ -56,7 +126,11 @@ int DBG_LEVEL = 0; # ifdef DEBUG_DECLARE_ONLY -extern void DBG_LOCAL (int level, const char *msg, ...); +extern void DBG_LOCAL (int level, const char *msg, ...) +#ifdef __GNUC__ +__attribute__ ((format (printf, 2, 3))) +#endif +; # else /* !DEBUG_DECLARE_ONLY */ @@ -65,6 +139,13 @@ extern void DBG_LOCAL (int level, const char *msg, ...); extern void sanei_debug_msg (int level, int max_level, const char *be, const char *fmt, va_list ap); +#ifdef __GNUC__ +# ifndef DEBUG_NOT_STATIC +static +# endif /* !DEBUG_NOT_STATIC */ +void DBG_LOCAL (int level, const char *msg, ...) __attribute__ ((format (printf, 2, 3))); +#endif /* __GNUC__ */ + # ifndef DEBUG_NOT_STATIC static # endif /* !DEBUG_NOT_STATIC */ @@ -78,14 +159,16 @@ DBG_LOCAL (int level, const char *msg, ...) va_end (ap); } -# endif /* DEBUG_NOT_STATIC */ +# endif /* DEBUG_DECLARE_ONLY */ # endif /* !STUBS */ + /** @hideinitializer*/ # define DBG DBG_LOCAL extern void sanei_init_debug (const char * backend, int * debug_level_var); + /** @hideinitializer*/ # define IF_DBG(x) x #endif /* NDEBUG */ diff --git a/include/sane/sanei_wire.h b/include/sane/sanei_wire.h index 3c380a0..95be5cf 100644 --- a/include/sane/sanei_wire.h +++ b/include/sane/sanei_wire.h @@ -16,6 +16,27 @@ along with sane; see the file COPYING. If not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + As a special exception, the authors of SANE give permission for + additional uses of the libraries contained in this release of SANE. + + The exception is that, if you link a SANE library with other files + to produce an executable, this does not by itself cause the + resulting executable to be covered by the GNU General Public + License. Your use of that executable is in no way restricted on + account of linking the SANE library code into it. + + This exception does not, however, invalidate any other reasons why + the executable file might be covered by the GNU General Public + License. + + If you submit changes to SANE to the maintainers to be included in + a subsequent release, you agree by submitting the changes that + those changes may be distributed with this exception intact. + + If you write modifications of your own for SANE, it is your choice + whether to permit this exception to apply to your modifications. + If you do not wish that, delete this exception notice. + Support routines to translate internal datatypes into a wire-format (used for RPCs and to save/restore options). */ @@ -24,6 +45,8 @@ #include +#define MAX_MEM (1024 * 1024) + typedef enum { WIRE_ENCODE = 0, @@ -43,6 +66,7 @@ typedef struct Wire int version; /* protocol version in use */ WireDirection direction; int status; + int allocated_memory; struct { WireCodecFunc w_byte; @@ -70,11 +94,15 @@ typedef struct Wire Wire; extern void sanei_w_init (Wire *w, void (*codec_init)(Wire *)); +extern void sanei_w_exit (Wire *w); extern void sanei_w_space (Wire *w, size_t howmuch); extern void sanei_w_void (Wire *w); extern void sanei_w_byte (Wire *w, SANE_Byte *v); extern void sanei_w_char (Wire *w, SANE_Char *v); extern void sanei_w_word (Wire *w, SANE_Word *v); +extern void sanei_w_bool (Wire *w, SANE_Bool *v); +extern void sanei_w_ptr (Wire *w, void **v, WireCodecFunc w_value, + size_t value_size); extern void sanei_w_string (Wire *w, SANE_String *v); extern void sanei_w_status (Wire *w, SANE_Status *v); extern void sanei_w_constraint_type (Wire *w, SANE_Constraint_Type *v); diff --git a/sanei/sanei_codec_bin.c b/sanei/sanei_codec_bin.c index c59a953..4347825 100644 --- a/sanei/sanei_codec_bin.c +++ b/sanei/sanei_codec_bin.c @@ -54,6 +54,9 @@ bin_w_byte (Wire *w, void *v) SANE_Byte *b = v; sanei_w_space (w, 1); + if (w->status) + return; + switch (w->direction) { case WIRE_ENCODE: @@ -82,8 +85,14 @@ bin_w_string (Wire *w, void *v) len = strlen (*s) + 1; } sanei_w_array (w, &len, v, w->codec.w_byte, 1); - if (w->direction == WIRE_DECODE && !len) - *s = 0; + + if (w->direction == WIRE_DECODE) + { + if (len == 0) + *s = 0; + else if (w->status == 0) + *(*s + len - 1) = '\0'; + } } static void @@ -92,6 +101,8 @@ bin_w_word (Wire *w, void *v) SANE_Word val, *word = v; sanei_w_space (w, 4); + if (w->status) + return; switch (w->direction) { case WIRE_ENCODE: diff --git a/sanei/sanei_thread.c b/sanei/sanei_thread.c index e3245cd..0c95fdb 100644 --- a/sanei/sanei_thread.c +++ b/sanei/sanei_thread.c @@ -1,5 +1,6 @@ /* sane - Scanner Access Now Easy. - Copyright (C) 2000 Yuri Dario + Copyright (C) 1998-2001 Yuri Dario + Copyright (C) 2003-2004 Gerhard Jaeger (pthread/process support) This file is part of the SANE package. This program is free software; you can redistribute it and/or @@ -37,72 +38,388 @@ If you write modifications of your own for SANE, it is your choice whether to permit this exception to apply to your modifications. If you do not wish that, delete this exception notice. + + OS/2 + 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 + macros. + + 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 "sane/config.h" #include #include +#include +#include #include -#include -#include #ifdef HAVE_UNISTD_H # include #endif - #ifdef HAVE_OS2_H -#define INCL_DOSPROCESS -#include +# define INCL_DOSPROCESS +# include +#endif +#if !defined USE_PTHREAD && !defined HAVE_OS2_H +# include +#endif +#if defined USE_PTHREAD +# include #endif +#define BACKEND_NAME sanei_thread /**< name of this module for debugging */ + +#include +#include "../include/sane/sanei_debug.h" #include "../include/sane/sanei_thread.h" +#ifndef _VAR_NOT_USED +# define _VAR_NOT_USED(x) ((x)=(x)) +#endif + +typedef struct { + + int (*func)( void* ); + SANE_Status status; + void *func_data; + +} ThreadDataDef, *pThreadDataDef; + +static ThreadDataDef td; + +/** for init issues - here only for the debug output + */ +void +sanei_thread_init( void ) +{ + DBG_INIT(); + + memset( &td, 0, sizeof(ThreadDataDef)); + td.status = SANE_STATUS_GOOD; +} + +SANE_Bool +sanei_thread_is_forked( void ) +{ +#if defined USE_PTHREAD || defined HAVE_OS2_H + return SANE_FALSE; +#else + return SANE_TRUE; +#endif +} + +int +sanei_thread_kill( int pid ) +{ + DBG(2, "sanei_thread_kill() will kill %d\n", (int)pid); +#ifdef USE_PTHREAD +#if defined (__APPLE__) && defined (__MACH__) + return pthread_kill((pthread_t)pid, SIGUSR2); +#else + return pthread_cancel((pthread_t)pid); +#endif +#elif defined HAVE_OS2_H + return DosKillThread(pid); +#else + return kill( pid, SIGTERM ); +#endif +} + +#ifdef HAVE_OS2_H + +static void +local_thread( void *arg ) +{ + pThreadDataDef ltd = (pThreadDataDef)arg; + + DBG( 2, "thread started, calling func() now...\n" ); + ltd->status = ltd->func( ltd->func_data ); + + DBG( 2, "func() done - status = %d\n", ltd->status ); + _endthread(); +} + /* * starts a new thread or process * parameters: - * start address of reader function - * arg_list pointer to scanner data structure + * star address of reader function + * args pointer to scanner data structure * -*/ + */ int -sanei_thread_begin( void (*start)(void *arg), - void *arg_list) +sanei_thread_begin( int (*func)(void *args), void* args ) { -#ifdef HAVE_OS2_H - return _beginthread( start, NULL, 64*1024, arg_list); + int pid; + + td.func = func; + td.func_data = args; + + pid = _beginthread( local_thread, NULL, 1024*1024, (void*)&td ); + if ( pid == -1 ) { + DBG( 1, "_beginthread() failed\n" ); + return -1; + } + + DBG( 2, "_beginthread() created thread %d\n", pid ); + return pid; +} + +int +sanei_thread_waitpid( int pid, int *status ) +{ + if (status) + *status = 0; + return pid; /* DosWaitThread( (TID*) &pid, DCWW_WAIT);*/ +} + +int +sanei_thread_sendsig( int pid, int sig ) +{ + return 0; +} + +#else /* HAVE_OS2_H */ + +#ifdef USE_PTHREAD + +/* seems to be undefined in MacOS X */ +#ifndef PTHREAD_CANCELED +# define PTHREAD_CANCELED ((void *) -1) +#endif + +/** + */ +#if defined (__APPLE__) && defined (__MACH__) +static void +thread_exit_handler( int signo ) +{ + DBG( 2, "signal(%i) caught, calling pthread_exit now...\n", signo ); + pthread_exit( PTHREAD_CANCELED ); +} +#endif + + +static void* +local_thread( void *arg ) +{ + static int status; + pThreadDataDef ltd = (pThreadDataDef)arg; + +#if defined (__APPLE__) && defined (__MACH__) + struct sigaction act; + + sigemptyset(&(act.sa_mask)); + act.sa_flags = 0; + act.sa_handler = thread_exit_handler; + sigaction( SIGUSR2, &act, 0 ); #else - return fork(); + int old; + + pthread_setcancelstate( PTHREAD_CANCEL_ENABLE, &old ); + pthread_setcanceltype ( PTHREAD_CANCEL_ASYNCHRONOUS, &old ); +#endif + + DBG( 2, "thread started, calling func() now...\n" ); + + status = ltd->func( ltd->func_data ); + + /* so sanei_thread_get_status() will work correctly... */ + ltd->status = status; + + DBG( 2, "func() done - status = %d\n", status ); + + /* return the status, so pthread_join is able to get it*/ + pthread_exit((void*)&status ); +} + +/** + */ +static void +restore_sigpipe( void ) +{ + struct sigaction act; + + if( sigaction( SIGPIPE, NULL, &act ) == 0 ) { + + if( act.sa_handler == SIG_IGN ) { + sigemptyset( &act.sa_mask ); + act.sa_flags = 0; + act.sa_handler = SIG_DFL; + + DBG( 2, "restoring SIGPIPE to SIG_DFL\n" ); + sigaction( SIGPIPE, &act, NULL ); + } + } +} + +#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 +sanei_thread_begin( int (func)(void *args), void* args ) +{ + int pid; +#ifdef USE_PTHREAD + struct sigaction act; + pthread_t thread; + + /* if signal handler for SIGPIPE is SIG_DFL, replace by SIG_IGN */ + if( sigaction( SIGPIPE, NULL, &act ) == 0 ) { + + if( act.sa_handler == SIG_DFL ) { + sigemptyset( &act.sa_mask ); + act.sa_flags = 0; + act.sa_handler = SIG_IGN; + + DBG( 2, "setting SIGPIPE to SIG_IGN\n" ); + sigaction( SIGPIPE, &act, NULL ); + } + } + + td.func = func; + td.func_data = args; + + pid = pthread_create( &thread, NULL, local_thread, &td ); + usleep( 1 ); + + if ( pid != 0 ) { + DBG( 1, "pthread_create() failed with %d\n", pid ); + return -1; + } + + DBG( 2, "pthread_create() created thread %d\n", (int)thread ); + return (int)thread; +#else + pid = fork(); + if( pid < 0 ) { + DBG( 1, "fork() failed\n" ); + return -1; + } + + if( pid == 0 ) { + + /* run in child context... */ + int status = func( args ); + + /* don't use exit() since that would run the atexit() handlers */ + _exit( status ); + } + + /* parents return */ + return pid; #endif } int -sanei_thread_kill( int pid, int sig) +sanei_thread_sendsig( int pid, int sig ) { -#ifdef HAVE_OS2_H - return DosKillThread( pid); +#ifdef USE_PTHREAD + DBG(2, "sanei_thread_sendsig() %d to thread(id=%d)\n", sig, pid); + return pthread_kill((pthread_t)pid, sig ); #else - return kill( pid, sig); + DBG(2, "sanei_thread_sendsig() %d to process (id=%d)\n", sig, pid); + return kill( pid, sig ); #endif } int -sanei_thread_waitpid( int pid, int *stat_loc, int options) +sanei_thread_waitpid( int pid, int *status ) { -#ifdef HAVE_OS2_H - return pid; /* DosWaitThread( (TID*) &pid, DCWW_WAIT);*/ +#ifdef USE_PTHREAD + int *ls; #else - return waitpid( pid, stat_loc, options); -#endif -} - -int -sanei_thread_wait( int *stat_loc) -{ -#ifdef HAVE_OS2_H - *stat_loc = 0; - return -1; /* return error because I don't know child pid */ -#else - return wait( stat_loc); + int ls; +#endif + int result, stat; + + stat = 0; + + DBG(2, "sanei_thread_waitpid() - %d\n", pid); +#ifdef USE_PTHREAD + result = pthread_join((pthread_t)pid, (void*)&ls ); + + if( 0 == result ) { + if( PTHREAD_CANCELED == ls ) { + DBG(2, "* thread has been canceled!\n" ); + stat = SANE_STATUS_GOOD; + } else { + stat = *ls; + } + DBG(2, "* result = %d (%p)\n", stat, (void*)status ); + result = pid; + } + /* call detach in any case to make sure that the thread resources + * will be freed, when the thread has terminated + */ + DBG(2, "* detaching thread(%d)\n", pid ); + pthread_detach((pthread_t)pid); + if (status) + *status = stat; + + restore_sigpipe(); +#else + result = waitpid( pid, &ls, 0 ); + if((result < 0) && (errno == ECHILD)) { + stat = SANE_STATUS_GOOD; + result = pid; + } else { + stat = eval_wp_result( pid, result, ls ); + DBG(2, "* result = %d (%p)\n", stat, (void*)status ); + } + if( status ) + *status = stat; +#endif + return result; +} + +#endif /* HAVE_OS2_H */ + +SANE_Status +sanei_thread_get_status( int pid ) +{ +#if defined USE_PTHREAD || defined HAVE_OS2_H + _VAR_NOT_USED( pid ); + + return td.status; +#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 } +/* END sanei_thread.c .......................................................*/ diff --git a/sanei/sanei_wire.c b/sanei/sanei_wire.c index 93d0a81..7f56639 100644 --- a/sanei/sanei_wire.c +++ b/sanei/sanei_wire.c @@ -49,28 +49,46 @@ #include #include "../include/sane/sanei_wire.h" +#define BACKEND_NAME sanei_wire +#include "../include/sane/sanei_debug.h" + void -sanei_w_space (Wire *w, size_t howmuch) +sanei_w_space (Wire * w, size_t howmuch) { size_t nbytes, left_over; int fd = w->io.fd; ssize_t nread, nwritten; + DBG (3, "sanei_w_space: %lu bytes for wire %d\n", (u_long) howmuch, fd); + + if (howmuch > w->buffer.size) + DBG (2, "sanei_w_space: bigger than buffer (%lu bytes), " + "may be flush()\n", (u_long) w->buffer.size); + if (w->status != 0) - return; + { + DBG (1, "sanei_w_space: wire is in invalid state %d\n", + w->status); + return; + } if (w->buffer.curr + howmuch > w->buffer.end) { + DBG (4, "sanei_w_space: free buffer size is %lu\n", + (u_long) (w->buffer.end - w->buffer.curr)); switch (w->direction) { case WIRE_ENCODE: nbytes = w->buffer.curr - w->buffer.start; w->buffer.curr = w->buffer.start; + DBG (4, "sanei_w_space: ENCODE: sending %lu bytes\n", + (u_long) nbytes); while (nbytes > 0) { nwritten = (*w->io.write) (fd, w->buffer.curr, nbytes); if (nwritten < 0) { + DBG (1, "sanei_w_space: ENCODE: write failed (%d)\n", errno); w->status = errno; return; } @@ -79,24 +97,37 @@ sanei_w_space (Wire *w, size_t howmuch) } w->buffer.curr = w->buffer.start; w->buffer.end = w->buffer.start + w->buffer.size; + DBG (4, "sanei_w_space: ENCODE: free buffer is now %lu\n", + (u_long) w->buffer.size); break; case WIRE_DECODE: left_over = w->buffer.end - w->buffer.curr; - if ((signed)left_over < 0) - return; - + if ((signed) left_over < 0) + { + DBG (1, "sanei_w_space: DECODE: buffer underflow\n"); + return; + } + if (left_over) - memcpy (w->buffer.start, w->buffer.curr, left_over); + { + DBG (4, "sanei_w_space: DECODE: %lu bytes left in buffer\n", + (u_long) left_over); + memmove (w->buffer.start, w->buffer.curr, left_over); + } w->buffer.curr = w->buffer.start; w->buffer.end = w->buffer.start + left_over; - do { + DBG (4, "sanei_w_space: DECODE: receiving data\n"); + do + { nread = (*w->io.read) (fd, w->buffer.end, w->buffer.size - left_over); if (nread <= 0) { + DBG (2, "sanei_w_space: DECODE: no data received (%d)\n", + errno); if (nread == 0) errno = EINVAL; w->status = errno; @@ -104,32 +135,43 @@ sanei_w_space (Wire *w, size_t howmuch) } left_over += nread; w->buffer.end += nread; - } while (left_over < howmuch); + } + while (left_over < howmuch); + DBG (4, "sanei_w_space: DECODE: %lu bytes read\n", + (u_long) (w->buffer.end - w->buffer.start)); break; case WIRE_FREE: + DBG (4, "sanei_w_space: FREE: doing nothing for free operation\n"); break; } } + DBG (4, "sanei_w_space: done\n"); } void -sanei_w_void (Wire *w) +sanei_w_void (Wire * w) { + DBG (3, "sanei_w_void: wire %d (void debug output)\n", w->io.fd); } void -sanei_w_array (Wire *w, SANE_Word *len_ptr, void **v, WireCodecFunc w_element, - size_t element_size) +sanei_w_array (Wire * w, SANE_Word * len_ptr, void **v, + WireCodecFunc w_element, size_t element_size) { SANE_Word len; char *val; int i; + DBG (3, "sanei_w_array: wire %d, elements of size %lu\n", w->io.fd, + (u_long) element_size); + if (w->direction == WIRE_FREE) { if (*len_ptr && *v) { + DBG (4, "sanei_w_array: FREE: freeing array (%d elements)\n", + *len_ptr); val = *v; for (i = 0; i < *len_ptr; ++i) { @@ -137,209 +179,334 @@ sanei_w_array (Wire *w, SANE_Word *len_ptr, void **v, WireCodecFunc w_element, val += element_size; } free (*v); + w->allocated_memory -= (*len_ptr * element_size); } + else + DBG (1, "sanei_w_array: FREE: tried to free array but *len_ptr or *v " + "was NULL\n"); + + DBG (4, "sanei_w_array: FREE: done\n"); return; } if (w->direction == WIRE_ENCODE) len = *len_ptr; - + DBG (4, "sanei_w_array: send/receive array length\n"); sanei_w_word (w, &len); + if (w->status) + { + DBG (1, "sanei_w_array: bad status: %d\n", w->status); + return; + } + DBG (4, "sanei_w_array: array has %d elements\n", len); + if (w->direction == WIRE_DECODE) { *len_ptr = len; if (len) { + if (((unsigned int) len) > MAX_MEM + || ((unsigned int) len * element_size) > MAX_MEM + || (w->allocated_memory + len * element_size) > MAX_MEM) + { + DBG (0, "sanei_w_array: DECODE: maximum amount of allocated memory " + "exceeded (limit: %u, new allocation: %u, total: %u bytes)\n", + MAX_MEM, len * element_size, MAX_MEM + len * element_size); + w->status = ENOMEM; + return; + } *v = malloc (len * element_size); if (*v == 0) { /* Malloc failed, so return an error. */ + DBG (1, "sanei_w_array: DECODE: not enough free memory\n"); w->status = ENOMEM; return; } + memset (*v, 0, len * element_size); + w->allocated_memory += (len * element_size); } else *v = 0; } val = *v; + DBG (4, "sanei_w_array: transferring array elements\n"); for (i = 0; i < len; ++i) { (*w_element) (w, val); val += element_size; + if (w->status) + { + DBG (1, "sanei_w_array: bad status: %d\n", w->status); + return; + } } + DBG (4, "sanei_w_array: done\n"); } void -sanei_w_ptr (Wire *w, void **v, WireCodecFunc w_value, size_t value_size) +sanei_w_ptr (Wire * w, void **v, WireCodecFunc w_value, size_t value_size) { SANE_Word is_null; + DBG (3, "sanei_w_ptr: wire %d, value pointer at is %lu bytes\n", w->io.fd, + (u_long) value_size); + if (w->direction == WIRE_FREE) { if (*v && value_size) { + DBG (4, "sanei_w_ptr: FREE: freeing value\n"); (*w_value) (w, *v); free (*v); + w->allocated_memory -= value_size; } + else + DBG (1, "sanei_w_ptr: FREE: tried to free value but *v or value_size " + "was NULL\n"); + + DBG (4, "sanei_w_ptr: FREE: done\n"); return; } if (w->direction == WIRE_ENCODE) is_null = (*v == 0); + DBG (4, "sanei_w_ptr: send/receive is_null\n"); sanei_w_word (w, &is_null); + if (w->status) + { + DBG (1, "sanei_w_ptr: bad status: %d\n", w->status); + return; + } if (!is_null) { if (w->direction == WIRE_DECODE) { + DBG (4, "sanei_w_ptr: DECODE: receive data pointed at\n"); + if (value_size > MAX_MEM) + { + DBG (0, "sanei_w_ptr: DECODE: maximum amount of allocated memory " + "exceeded (limit: %u, new allocation: %u, total: %u bytes)\n", + MAX_MEM, value_size, (w->allocated_memory + value_size)); + w->status = ENOMEM; + return; + } + *v = malloc (value_size); if (*v == 0) { /* Malloc failed, so return an error. */ + DBG (1, "sanei_w_ptr: DECODE: not enough free memory\n"); w->status = ENOMEM; return; } + w->allocated_memory += value_size; + memset (*v, 0, value_size); } (*w_value) (w, *v); } else if (w->direction == WIRE_DECODE) *v = 0; + + DBG (4, "sanei_w_ptr: done\n"); } void -sanei_w_byte (Wire *w, SANE_Byte *v) +sanei_w_byte (Wire * w, SANE_Byte * v) { + DBG (3, "sanei_w_byte: wire %d\n", w->io.fd); (*w->codec.w_byte) (w, v); + if (w->direction != WIRE_FREE) + DBG (4, "sanei_w_byte: value = %d\n", *v); } void -sanei_w_char (Wire *w, SANE_Char *v) +sanei_w_char (Wire * w, SANE_Char * v) { + DBG (3, "sanei_w_char: wire %d\n", w->io.fd); (*w->codec.w_char) (w, v); + if (w->direction != WIRE_FREE) + DBG (4, "sanei_w_char: value = %d\n", *v); } void -sanei_w_word (Wire *w, SANE_Word *v) +sanei_w_word (Wire * w, SANE_Word * v) { + DBG (3, "sanei_w_word: wire %d\n", w->io.fd); (*w->codec.w_word) (w, v); + if (w->direction != WIRE_FREE) + DBG (4, "sanei_w_word: value = %d\n", *v); } void -sanei_w_string (Wire *w, SANE_String *v) +sanei_w_string (Wire * w, SANE_String * v) { + DBG (3, "sanei_w_string: wire %d\n", w->io.fd); (*w->codec.w_string) (w, v); + if (w->direction != WIRE_FREE && w->status == 0) + DBG (4, "sanei_w_string: value = %s\n", *v); } void -sanei_w_status (Wire *w, SANE_Status *v) +sanei_w_status (Wire * w, SANE_Status * v) { SANE_Word word = *v; + DBG (3, "sanei_w_status: wire %d\n", w->io.fd); + sanei_w_word (w, &word); if (w->direction == WIRE_DECODE) *v = word; + + if (w->direction != WIRE_FREE) + DBG (4, "sanei_w_status: value = %d\n", word); } void -sanei_w_bool (Wire *w, SANE_Bool *v) +sanei_w_bool (Wire * w, SANE_Bool * v) { SANE_Word word = *v; + DBG (3, "sanei_w_bool: wire %d\n", w->io.fd); + sanei_w_word (w, &word); + if (w->direction == WIRE_DECODE) + *v = word; + + if (w->direction != WIRE_FREE) + DBG (4, "sanei_w_bool: value = %s\n", + ((word == SANE_TRUE) ? ("true") : ("false"))); +} + +void +sanei_w_constraint_type (Wire * w, SANE_Constraint_Type * v) +{ + SANE_Word word = *v; + + DBG (3, "sanei_w_constraint_type: wire %d\n", w->io.fd); + sanei_w_word (w, &word); if (w->direction == WIRE_DECODE) *v = word; + + if (w->direction != WIRE_FREE) + DBG (4, "sanei_w_constraint_type: value = %d\n", word); } void -sanei_w_constraint_type (Wire *w, SANE_Constraint_Type *v) +sanei_w_value_type (Wire * w, SANE_Value_Type * v) { SANE_Word word = *v; + DBG (3, "sanei_w_value_type: wire %d\n", w->io.fd); + sanei_w_word (w, &word); if (w->direction == WIRE_DECODE) *v = word; + if (w->direction != WIRE_FREE) + DBG (4, "sanei_w_value_type: value = %d\n", word); } void -sanei_w_value_type (Wire *w, SANE_Value_Type *v) +sanei_w_unit (Wire * w, SANE_Unit * v) { SANE_Word word = *v; + DBG (3, "sanei_w_unit: wire %d\n", w->io.fd); + sanei_w_word (w, &word); + if (w->direction == WIRE_DECODE) + *v = word; + + if (w->direction != WIRE_FREE) + DBG (4, "sanei_w_unit: value = %d\n", word); + /* gosh... all the sane_w_something should be a macro or something */ +} + +void +sanei_w_action (Wire * w, SANE_Action * v) +{ + SANE_Word word = *v; + + DBG (3, "sanei_w_action: wire %d\n", w->io.fd); + sanei_w_word (w, &word); if (w->direction == WIRE_DECODE) *v = word; + + if (w->direction != WIRE_FREE) + DBG (4, "sanei_w_action: value = %d\n", word); } void -sanei_w_unit (Wire *w, SANE_Unit *v) +sanei_w_frame (Wire * w, SANE_Frame * v) { SANE_Word word = *v; + DBG (3, "sanei_w_frame: wire %d\n", w->io.fd); + sanei_w_word (w, &word); if (w->direction == WIRE_DECODE) *v = word; + + if (w->direction != WIRE_FREE) + DBG (4, "sanei_w_frame: value = %d\n", word); } void -sanei_w_action (Wire *w, SANE_Action *v) -{ - SANE_Word word = *v; - - sanei_w_word (w, &word); - if (w->direction == WIRE_DECODE) - *v = word; -} - -void -sanei_w_frame (Wire *w, SANE_Frame *v) -{ - SANE_Word word = *v; - - sanei_w_word (w, &word); - if (w->direction == WIRE_DECODE) - *v = word; -} - -void -sanei_w_range (Wire *w, SANE_Range *v) +sanei_w_range (Wire * w, SANE_Range * v) { + DBG (3, "sanei_w_range: wire %d\n", w->io.fd); sanei_w_word (w, &v->min); sanei_w_word (w, &v->max); sanei_w_word (w, &v->quant); + if (w->direction != WIRE_FREE) + DBG (4, "sanei_w_range: min/max/step = %f/%f/%f\n", + SANE_UNFIX (v->min), SANE_UNFIX (v->max), SANE_UNFIX (v->quant)); } void -sanei_w_device (Wire *w, SANE_Device *v) +sanei_w_device (Wire * w, SANE_Device * v) { - sanei_w_string (w, (SANE_String *) &v->name); - sanei_w_string (w, (SANE_String *) &v->vendor); - sanei_w_string (w, (SANE_String *) &v->model); - sanei_w_string (w, (SANE_String *) &v->type); + DBG (3, "sanei_w_device: wire %d\n", w->io.fd); + sanei_w_string (w, (SANE_String *) & v->name); + sanei_w_string (w, (SANE_String *) & v->vendor); + sanei_w_string (w, (SANE_String *) & v->model); + sanei_w_string (w, (SANE_String *) & v->type); + if (w->direction != WIRE_FREE) + DBG (4, "sanei_w_device: %s %s from %s (%s)\n", v->name, v->model, + v->vendor, v->type); } void -sanei_w_device_ptr (Wire *w, SANE_Device **v) +sanei_w_device_ptr (Wire * w, SANE_Device ** v) { - sanei_w_ptr (w, (void **) v, - (WireCodecFunc) sanei_w_device, sizeof (**v)); + DBG (3, "sanei_w_device_ptr: wire %d\n", w->io.fd); + sanei_w_ptr (w, (void **) v, (WireCodecFunc) sanei_w_device, sizeof (**v)); + if (w->direction != WIRE_FREE) + DBG (4, "sanei_w_device_ptr: device struct at %p\n", *v); } void -sanei_w_option_descriptor (Wire *w, SANE_Option_Descriptor *v) +sanei_w_option_descriptor (Wire * w, SANE_Option_Descriptor * v) { SANE_Word len; - sanei_w_string (w, (SANE_String *) &v->name); - sanei_w_string (w, (SANE_String *) &v->title); - sanei_w_string (w, (SANE_String *) &v->desc); + DBG (3, "sanei_w_option_descriptor: wire %d\n", w->io.fd); + + sanei_w_string (w, (SANE_String *) & v->name); + sanei_w_string (w, (SANE_String *) & v->title); + sanei_w_string (w, (SANE_String *) & v->desc); sanei_w_value_type (w, &v->type); sanei_w_unit (w, &v->unit); sanei_w_word (w, &v->size); sanei_w_word (w, &v->cap); sanei_w_constraint_type (w, &v->constraint_type); - + + if (w->direction != WIRE_FREE) + DBG (4, "sanei_w_option_descriptor: option %s\n", v->name); + switch (v->constraint_type) { case SANE_CONSTRAINT_NONE: @@ -354,117 +521,174 @@ sanei_w_option_descriptor (Wire *w, SANE_Option_Descriptor *v) if (w->direction != WIRE_DECODE) len = v->constraint.word_list[0] + 1; sanei_w_array (w, &len, (void **) &v->constraint.word_list, - w->codec.w_word, sizeof(SANE_Word)); + w->codec.w_word, sizeof (SANE_Word)); break; case SANE_CONSTRAINT_STRING_LIST: if (w->direction != WIRE_DECODE) { for (len = 0; v->constraint.string_list[len]; ++len); - ++len; /* send NULL string, too */ + ++len; /* send NULL string, too */ } sanei_w_array (w, &len, (void **) &v->constraint.string_list, - w->codec.w_string, sizeof(SANE_String)); + w->codec.w_string, sizeof (SANE_String)); break; } + DBG (4, "sanei_w_option_descriptor: done\n"); } void -sanei_w_option_descriptor_ptr (Wire *w, SANE_Option_Descriptor **v) +sanei_w_option_descriptor_ptr (Wire * w, SANE_Option_Descriptor ** v) { + DBG (3, "sanei_w_option_descriptor_ptr: wire %d\n", w->io.fd); sanei_w_ptr (w, (void **) v, (WireCodecFunc) sanei_w_option_descriptor, sizeof (**v)); + DBG (4, "sanei_w_option_descriptor_ptr: done\n"); } void -sanei_w_parameters (Wire *w, SANE_Parameters *v) +sanei_w_parameters (Wire * w, SANE_Parameters * v) { + DBG (3, "sanei_w_parameters: wire %d\n", w->io.fd); sanei_w_frame (w, &v->format); sanei_w_bool (w, &v->last_frame); sanei_w_word (w, &v->bytes_per_line); sanei_w_word (w, &v->pixels_per_line); sanei_w_word (w, &v->lines); sanei_w_word (w, &v->depth); + if (w->direction != WIRE_FREE) + DBG (4, + "sanei_w_parameters: format/last/bpl/ppl/lines/depth = " + "%d/%d/%d/%d/%d/%d\n", v->format, v->last_frame, v->bytes_per_line, + v->pixels_per_line, v->lines, v->depth); } static void -flush (Wire *w) +flush (Wire * w) { + DBG (3, "flush: wire %d\n", w->io.fd); if (w->direction == WIRE_ENCODE) sanei_w_space (w, w->buffer.size + 1); else if (w->direction == WIRE_DECODE) w->buffer.curr = w->buffer.end = w->buffer.start; + if (w->status != 0) + DBG (2, "flush: error status %d\n", w->status); + DBG (4, "flush: wire flushed\n"); } void -sanei_w_set_dir (Wire *w, WireDirection dir) +sanei_w_set_dir (Wire * w, WireDirection dir) { + DBG (3, "sanei_w_set_dir: wire %d, old direction WIRE_%s\n", w->io.fd, + w->direction == WIRE_ENCODE ? "ENCODE" : + (w->direction == WIRE_DECODE ? "DECODE" : "FREE")); + if (w->direction == WIRE_DECODE && w->buffer.curr != w->buffer.end) + DBG (1, "sanei_w_set_dir: WARNING: will delete %lu bytes from buffer\n", + (u_long) (w->buffer.end - w->buffer.curr)); flush (w); w->direction = dir; + DBG (4, "sanei_w_set_dir: direction changed\n"); flush (w); + DBG (3, "sanei_w_set_dir: wire %d, new direction WIRE_%s\n", w->io.fd, + dir == WIRE_ENCODE ? "ENCODE" : + (dir == WIRE_DECODE ? "DECODE" : "FREE")); } void -sanei_w_call (Wire *w, +sanei_w_call (Wire * w, SANE_Word procnum, WireCodecFunc w_arg, void *arg, WireCodecFunc w_reply, void *reply) { + + DBG (3, "sanei_w_call: wire %d (old status %d)\n", w->io.fd, w->status); w->status = 0; sanei_w_set_dir (w, WIRE_ENCODE); + DBG (4, "sanei_w_call: sending request (procedure number: %d)\n", procnum); sanei_w_word (w, &procnum); (*w_arg) (w, arg); if (w->status == 0) { + DBG (4, "sanei_w_call: receiving reply\n"); sanei_w_set_dir (w, WIRE_DECODE); (*w_reply) (w, reply); } + + if (w->status != 0) + DBG (2, "sanei_w_call: error status %d\n", w->status); + DBG (4, "sanei_w_call: done\n"); } void -sanei_w_reply (Wire *w, WireCodecFunc w_reply, void *reply) +sanei_w_reply (Wire * w, WireCodecFunc w_reply, void *reply) { + DBG (3, "sanei_w_reply: wire %d (old status %d)\n", w->io.fd, w->status); w->status = 0; sanei_w_set_dir (w, WIRE_ENCODE); (*w_reply) (w, reply); flush (w); + if (w->status != 0) + DBG (2, "sanei_w_reply: error status %d\n", w->status); + DBG (4, "sanei_w_reply: done\n"); } void -sanei_w_free (Wire *w, WireCodecFunc w_reply, void *reply) +sanei_w_free (Wire * w, WireCodecFunc w_reply, void *reply) { WireDirection saved_dir = w->direction; + DBG (3, "sanei_w_free: wire %d\n", w->io.fd); + w->direction = WIRE_FREE; (*w_reply) (w, reply); w->direction = saved_dir; + + if (w->status != 0) + DBG (2, "sanei_w_free: error status %d\n", w->status); + DBG (4, "sanei_w_free: done\n"); } void -sanei_w_init (Wire *w, void (*codec_init_func)(Wire *)) +sanei_w_init (Wire * w, void (*codec_init_func) (Wire *)) { + DBG_INIT (); + + DBG (3, "sanei_w_init: initializing\n"); w->status = 0; w->direction = WIRE_ENCODE; w->buffer.size = 8192; w->buffer.start = malloc (w->buffer.size); - + if (w->buffer.start == 0) - /* Malloc failed, so return an error. */ - w->status = ENOMEM; + { + /* Malloc failed, so return an error. */ + w->status = ENOMEM; + DBG (1, "sanei_w_init: not enough free memory\n"); + } w->buffer.curr = w->buffer.start; w->buffer.end = w->buffer.start + w->buffer.size; if (codec_init_func != 0) - (*codec_init_func) (w); + { + DBG (4, "sanei_w_init: initializing codec\n"); + (*codec_init_func) (w); + } + w->allocated_memory = 0; + DBG (4, "sanei_w_init: done\n"); } void -sanei_w_exit (Wire *w) +sanei_w_exit (Wire * w) { + DBG (3, "sanei_w_exit: wire %d\n", w->io.fd); if (w->buffer.start) - free(w->buffer.start); + { + DBG (4, "sanei_w_exit: freeing buffer\n"); + free (w->buffer.start); + } w->buffer.start = 0; w->buffer.size = 0; + DBG (4, "sanei_w_exit: done\n"); }