sanei resync with sane-backends, fixes a deadlock between xscanimage and

saned when scanning over the network.
merge-requests/2/head
Julien BLACHE 2004-12-11 08:20:52 +00:00
rodzic eff8cec616
commit 18c43a087d
9 zmienionych plików z 1002 dodań i 133 usunięć

Wyświetl plik

@ -1,3 +1,7 @@
2004-12-11 Julien Blache <jb@jblache.org>
* sanei resync with sane-backends, fixes a deadlock between xscanimage
and saned when scanning over the network.
2004-10-30 Henning Meier-Geinitz <henning@meier-geinitz.de>
* doc/scanadf.man src/scanadf.c: Wait for scan-scripts so all

Wyświetl plik

@ -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 <a
* href="http://www.sane-project.org/html/">the SANE webserver</a>.
* - Information on how to write a backend: <a
* href="../backend-writing.txt">backend-writing.txt</a>.
* - General SANE documentation is on <a
* href="http://www.sane-project.org/docs.html>the SANE documentation
* page</a>.
*
* @section contact Contact
*
* The common way to contact the developers of SANE is the sane-devel
* mailing list. See the <a
* href="http://www.sane-project.org/mailing-lists.html">mailing list webpage</a>
* for details. That's the place to ask questions, report bugs, or announce
* a new backend.
*
*/
#ifndef sanei_h
#define sanei_h
#include <sane/sane.h>
/* 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);

Wyświetl plik

@ -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 */

Wyświetl plik

@ -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 */

Wyświetl plik

@ -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 <sane/sanei.h>
/* 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 */

Wyświetl plik

@ -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 <sys/types.h>
#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);

Wyświetl plik

@ -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:

Wyświetl plik

@ -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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/wait.h>
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
#ifdef HAVE_OS2_H
#define INCL_DOSPROCESS
#include <os2.h>
# define INCL_DOSPROCESS
# include <os2.h>
#endif
#if !defined USE_PTHREAD && !defined HAVE_OS2_H
# include <sys/wait.h>
#endif
#if defined USE_PTHREAD
# include <pthread.h>
#endif
#define BACKEND_NAME sanei_thread /**< name of this module for debugging */
#include <sane/sane.h>
#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 .......................................................*/

Wyświetl plik

@ -49,28 +49,46 @@
#include <sane/sane.h>
#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");
}