Adding upstream version 0.2.
Signed-off-by: Daniel Baumann <daniel@debian.org>
This commit is contained in:
parent
63d771d1a1
commit
e748b84dff
21 changed files with 1267 additions and 2163 deletions
475
main.cc
475
main.cc
|
@ -1,6 +1,6 @@
|
|||
/* Plzip - A parallel version of the lzip data compressor
|
||||
Copyright (C) 2009 Laszlo Ersek.
|
||||
Copyright (C) 2009 Antonio Diaz Diaz.
|
||||
Copyright (C) 2009, 2010 Antonio Diaz Diaz.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
@ -29,14 +29,14 @@
|
|||
#include <cerrno>
|
||||
#include <climits>
|
||||
#include <csignal>
|
||||
#include <cstdarg> /* va_list */
|
||||
#include <cstdarg>
|
||||
#include <cstddef>
|
||||
#include <cstdio> /* flockfile() */
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <cstring> /* strerror() */
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <fcntl.h> /* open() */
|
||||
#include <fcntl.h>
|
||||
#include <stdint.h>
|
||||
#include <pthread.h>
|
||||
#include <unistd.h>
|
||||
|
@ -63,8 +63,6 @@
|
|||
#endif
|
||||
|
||||
void internal_error( const char * msg );
|
||||
int readblock( const int fd, char * buf, const int size ) throw();
|
||||
int writeblock( const int fd, const char * buf, const int size ) throw();
|
||||
|
||||
|
||||
namespace {
|
||||
|
@ -72,7 +70,7 @@ namespace {
|
|||
const char * invocation_name = 0;
|
||||
const char * const Program_name = "Plzip";
|
||||
const char * const program_name = "plzip";
|
||||
const char * const program_year = "2009";
|
||||
const char * const program_year = "2010";
|
||||
|
||||
struct { const char * from; const char * to; } const known_extensions[] = {
|
||||
{ ".lz", "" },
|
||||
|
@ -89,7 +87,6 @@ enum Mode { m_compress = 0, m_decompress, m_test };
|
|||
|
||||
std::string output_filename;
|
||||
int outhandle = -1;
|
||||
int verbosity = 0;
|
||||
bool delete_output_on_interrupt = false;
|
||||
|
||||
class Pretty_print
|
||||
|
@ -137,13 +134,13 @@ void show_help() throw()
|
|||
// std::printf( " -b, --member-size=<n> set member size limit in bytes\n" );
|
||||
std::printf( " -c, --stdout send output to standard output\n" );
|
||||
std::printf( " -d, --decompress decompress\n" );
|
||||
// std::printf( " -f, --force overwrite existing output files\n" );
|
||||
// std::printf( " -k, --keep keep (don't delete) input files\n" );
|
||||
// std::printf( " -m, --match-length=<n> set match length limit in bytes [80]\n" );
|
||||
std::printf( " -f, --force overwrite existing output files\n" );
|
||||
std::printf( " -k, --keep keep (don't delete) input files\n" );
|
||||
std::printf( " -m, --match-length=<n> set match length limit in bytes [80]\n" );
|
||||
std::printf( " -n, --threads=<n> set the number of (de)compression threads\n" );
|
||||
// std::printf( " -o, --output=<file> if reading stdin, place the output into <file>\n" );
|
||||
std::printf( " -o, --output=<file> if reading stdin, place the output into <file>\n" );
|
||||
std::printf( " -q, --quiet suppress all messages\n" );
|
||||
// std::printf( " -s, --dictionary-size=<n> set dictionary size limit in bytes [8MiB]\n" );
|
||||
std::printf( " -s, --dictionary-size=<n> set dictionary size limit in bytes [8MiB]\n" );
|
||||
// std::printf( " -S, --volume-size=<n> set volume size limit in bytes\n" );
|
||||
std::printf( " -t, --test test compressed file integrity\n" );
|
||||
std::printf( " -v, --verbose be verbose (a 2nd -v gives more)\n" );
|
||||
|
@ -159,7 +156,7 @@ void show_help() throw()
|
|||
std::printf( "Numbers may be followed by a multiplier: k = kB = 10^3 = 1000,\n" );
|
||||
std::printf( "Ki = KiB = 2^10 = 1024, M = 10^6, Mi = 2^20, G = 10^9, Gi = 2^30, etc...\n" );
|
||||
std::printf( "\nReport bugs to lzip-bug@nongnu.org\n" );
|
||||
std::printf( "Lzip home page: http://www.nongnu.org/lzip/lzip.html\n" );
|
||||
std::printf( "Plzip home page: http://www.nongnu.org/lzip/plzip.html\n" );
|
||||
}
|
||||
|
||||
|
||||
|
@ -209,7 +206,7 @@ long long getnum( const char * ptr, const int bs = 0,
|
|||
break;
|
||||
case 'k': if( factor == 1000 ) exponent = 1; else bad_multiplier = true;
|
||||
break;
|
||||
default: bad_multiplier = true;
|
||||
default : bad_multiplier = true;
|
||||
}
|
||||
if( bad_multiplier )
|
||||
{
|
||||
|
@ -236,9 +233,10 @@ int get_dict_size( const char * arg ) throw()
|
|||
{
|
||||
char *tail;
|
||||
int bits = std::strtol( arg, &tail, 0 );
|
||||
if( bits >= min_dictionary_bits && bits <= max_dictionary_bits && *tail == 0 )
|
||||
if( bits >= LZ_min_dictionary_bits() &&
|
||||
bits <= LZ_max_dictionary_bits() && *tail == 0 )
|
||||
return ( 1 << bits );
|
||||
return getnum( arg, 0, min_dictionary_size, max_dictionary_size );
|
||||
return getnum( arg, 0, LZ_min_dictionary_size(), LZ_max_dictionary_size() );
|
||||
}
|
||||
|
||||
|
||||
|
@ -380,75 +378,59 @@ void cleanup_and_fail( const int retval ) throw()
|
|||
|
||||
|
||||
// Set permissions, owner and times.
|
||||
void close_and_set_permissions( const struct stat * in_statsp, int * retvalp )
|
||||
void close_and_set_permissions( const struct stat * const in_statsp )
|
||||
{
|
||||
int tmp = 0;
|
||||
bool error = false;
|
||||
if( in_statsp )
|
||||
{
|
||||
if( fchmod( outhandle, in_statsp->st_mode ) != 0 ) tmp = 1;
|
||||
if( !tmp ) (void)fchown( outhandle, in_statsp->st_uid, in_statsp->st_gid );
|
||||
if( fchmod( outhandle, in_statsp->st_mode ) != 0 ) error = true;
|
||||
else (void)fchown( outhandle, in_statsp->st_uid, in_statsp->st_gid );
|
||||
// fchown will in many cases return with EPERM, which can be safely ignored.
|
||||
}
|
||||
if( close( outhandle ) == 0 ) outhandle = -1;
|
||||
else cleanup_and_fail( 1 );
|
||||
delete_output_on_interrupt = false;
|
||||
if( !in_statsp ) return;
|
||||
if( !tmp )
|
||||
if( !error )
|
||||
{
|
||||
struct utimbuf t;
|
||||
t.actime = in_statsp->st_atime;
|
||||
t.modtime = in_statsp->st_mtime;
|
||||
if( utime( output_filename.c_str(), &t ) != 0 ) tmp = 1;
|
||||
if( utime( output_filename.c_str(), &t ) != 0 ) error = true;
|
||||
}
|
||||
if( tmp )
|
||||
if( error )
|
||||
{
|
||||
if( tmp > *retvalp ) *retvalp = tmp;
|
||||
show_error( "I can't change output file attributes." );
|
||||
cleanup_and_fail( *retvalp );
|
||||
cleanup_and_fail( 1 );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int decompress( const int inhandle, const Pretty_print & pp,
|
||||
const bool testing )
|
||||
int do_decompress( LZ_Decoder * const decoder, const int inhandle,
|
||||
const Pretty_print & pp, const bool testing )
|
||||
{
|
||||
void * decoder = LZ_decompress_open();
|
||||
if( !decoder || LZ_decompress_errno( decoder ) != LZ_ok )
|
||||
{
|
||||
LZ_decompress_close( decoder );
|
||||
pp( "not enough memory. Find a machine with more memory" );
|
||||
return 1;
|
||||
}
|
||||
if( verbosity >= 1 ) pp();
|
||||
|
||||
const int in_buffer_size = 65536, out_buffer_size = 8 * in_buffer_size;
|
||||
uint8_t in_buffer[in_buffer_size], out_buffer[out_buffer_size];
|
||||
int in_pos = 0, in_stream_pos = 0;
|
||||
bool finished = false;
|
||||
|
||||
if( verbosity >= 1 ) pp();
|
||||
while( true )
|
||||
{
|
||||
int in_size = 0;
|
||||
if( !finished )
|
||||
int in_size = std::min( LZ_decompress_write_size( decoder ), in_buffer_size );
|
||||
if( in_size > 0 )
|
||||
{
|
||||
if( in_stream_pos == 0 )
|
||||
in_stream_pos = readblock( inhandle, (char *)in_buffer, in_buffer_size );
|
||||
if( in_pos < in_stream_pos )
|
||||
{
|
||||
in_size = LZ_decompress_write( decoder, in_buffer + in_pos, in_stream_pos - in_pos );
|
||||
in_pos += in_size;
|
||||
}
|
||||
if( in_pos >= in_stream_pos )
|
||||
{
|
||||
if( in_stream_pos < in_buffer_size )
|
||||
{ finished = true; LZ_decompress_finish( decoder ); }
|
||||
in_stream_pos = 0; in_pos = 0;
|
||||
}
|
||||
const int max_in_size = in_size;
|
||||
in_size = readblock( inhandle, (char *)in_buffer, max_in_size );
|
||||
if( in_size != max_in_size && errno )
|
||||
{ pp(); show_error( "read error", errno ); return 1; }
|
||||
if( in_size == 0 ) LZ_decompress_finish( decoder );
|
||||
else if( in_size != LZ_decompress_write( decoder, in_buffer, in_size ) )
|
||||
internal_error( "library error (LZ_decompress_write)" );
|
||||
}
|
||||
int out_size = LZ_decompress_read( decoder, out_buffer, out_buffer_size );
|
||||
// std::fprintf( stderr, "%5d in_size, %6d out_size.\n", in_size, out_size );
|
||||
if( out_size < 0 )
|
||||
{
|
||||
const LZ_errno lz_errno = LZ_decompress_errno( decoder );
|
||||
const LZ_Errno lz_errno = LZ_decompress_errno( decoder );
|
||||
if( lz_errno == LZ_header_error )
|
||||
{
|
||||
if( LZ_decompress_total_out_size( decoder ) > 0 )
|
||||
|
@ -461,15 +443,18 @@ int decompress( const int inhandle, const Pretty_print & pp,
|
|||
pp( "not enough memory. Find a machine with more memory" );
|
||||
return 1;
|
||||
}
|
||||
pp();
|
||||
if( lz_errno == LZ_unexpected_eof )
|
||||
{
|
||||
if( verbosity >= 0 )
|
||||
{ pp();
|
||||
std::fprintf( stderr, "file ends unexpectedly at pos %lld\n",
|
||||
LZ_decompress_total_in_size( decoder ) ); }
|
||||
std::fprintf( stderr, "file ends unexpectedly at pos %lld\n",
|
||||
LZ_decompress_total_in_size( decoder ) );
|
||||
return 2;
|
||||
}
|
||||
pp(); show_error( "read error", errno ); return 1;
|
||||
if( verbosity >= 0 )
|
||||
std::fprintf( stderr, "LZ_decompress_read error: %s.\n",
|
||||
LZ_strerror( LZ_decompress_errno( decoder ) ) );
|
||||
return 1;
|
||||
}
|
||||
else if( out_size > 0 && outhandle >= 0 )
|
||||
{
|
||||
|
@ -478,17 +463,33 @@ int decompress( const int inhandle, const Pretty_print & pp,
|
|||
{ pp(); show_error( "write error", errno ); return 1; }
|
||||
}
|
||||
if( LZ_decompress_finished( decoder ) == 1 ) break;
|
||||
if( finished && in_size == 0 && out_size == 0 )
|
||||
if( in_size == 0 && out_size == 0 )
|
||||
internal_error( "library error (LZ_decompress_read)" );
|
||||
}
|
||||
if( verbosity >= 1 )
|
||||
{ if( testing ) std::fprintf( stderr, "ok\n" );
|
||||
else std::fprintf( stderr, "done\n" ); }
|
||||
LZ_decompress_close( decoder );
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int decompress( const int inhandle, const Pretty_print & pp,
|
||||
const bool testing )
|
||||
{
|
||||
LZ_Decoder * const decoder = LZ_decompress_open();
|
||||
int retval;
|
||||
|
||||
if( !decoder || LZ_decompress_errno( decoder ) != LZ_ok )
|
||||
{
|
||||
pp( "not enough memory" );
|
||||
retval = 1;
|
||||
}
|
||||
else retval = do_decompress( decoder, inhandle, pp, testing );
|
||||
LZ_decompress_close( decoder );
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
extern "C" void signal_handler( int ) throw()
|
||||
{
|
||||
show_error( "Control-C or similar caught, quitting." );
|
||||
|
@ -506,6 +507,9 @@ void set_signals() throw()
|
|||
} // end namespace
|
||||
|
||||
|
||||
int verbosity = 0;
|
||||
|
||||
|
||||
void Pretty_print::operator()( const char * const msg ) const throw()
|
||||
{
|
||||
if( verbosity >= 0 )
|
||||
|
@ -523,6 +527,30 @@ void Pretty_print::operator()( const char * const msg ) const throw()
|
|||
}
|
||||
|
||||
|
||||
void show_error( const char * msg, const int errcode, const bool help ) throw()
|
||||
{
|
||||
if( verbosity >= 0 )
|
||||
{
|
||||
if( msg && msg[0] != 0 )
|
||||
{
|
||||
std::fprintf( stderr, "%s: %s", program_name, msg );
|
||||
if( errcode > 0 ) std::fprintf( stderr, ": %s", std::strerror( errcode ) );
|
||||
std::fprintf( stderr, "\n" );
|
||||
}
|
||||
if( help && invocation_name && invocation_name[0] != 0 )
|
||||
std::fprintf( stderr, "Try `%s --help' for more information.\n", invocation_name );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void internal_error( const char * msg )
|
||||
{
|
||||
std::string s( "internal error: " ); s += msg;
|
||||
show_error( s.c_str() );
|
||||
std::exit( 3 );
|
||||
}
|
||||
|
||||
|
||||
/* Private stuff needed by fatal(). */
|
||||
static pthread_t main_thread;
|
||||
|
||||
|
@ -530,25 +558,21 @@ static pid_t pid;
|
|||
|
||||
|
||||
/* Public utility variables and functions. */
|
||||
void *(*mallocf)(size_t size);
|
||||
void (*freef)(void *ptr);
|
||||
|
||||
|
||||
/*
|
||||
This can be called from any thread, main thread or sub-threads alike, since
|
||||
they all call common helper functions that call fatal() in case of an error.
|
||||
*/
|
||||
void
|
||||
fatal(void)
|
||||
void fatal()
|
||||
{
|
||||
if( pthread_equal(pthread_self(), main_thread) )
|
||||
cleanup_and_fail( 1 );
|
||||
else
|
||||
{
|
||||
if (0 == kill(pid, SIGUSR1))
|
||||
if( 0 == kill(pid, SIGUSR1) )
|
||||
pthread_exit(0);
|
||||
}
|
||||
_exit(EXIT_FAILURE);
|
||||
_exit( 1 );
|
||||
}
|
||||
|
||||
|
||||
|
@ -572,67 +596,51 @@ fail(const char *fmt, int err, ...)
|
|||
}
|
||||
|
||||
|
||||
void *
|
||||
xalloc(size_t size)
|
||||
{
|
||||
void *ret = (*mallocf)(size);
|
||||
|
||||
if (0 == ret) {
|
||||
fail("(*mallocf)()", errno);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
xinit(Cond *cond)
|
||||
{
|
||||
int ret;
|
||||
pthread_mutexattr_t attr;
|
||||
|
||||
ret = pthread_mutexattr_init(&attr);
|
||||
if (0 != ret) {
|
||||
int ret = pthread_mutexattr_init(&attr);
|
||||
if( ret != 0 ) {
|
||||
fail("pthread_mutexattr_init()", ret);
|
||||
}
|
||||
|
||||
ret = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK);
|
||||
if (0 != ret) {
|
||||
if( ret != 0 ) {
|
||||
fail("pthread_mutexattr_settype()", ret);
|
||||
}
|
||||
|
||||
ret = pthread_mutex_init(&cond->lock, &attr);
|
||||
if (0 != ret) {
|
||||
if( ret != 0 ) {
|
||||
fail("pthread_mutex_init()", ret);
|
||||
}
|
||||
|
||||
ret = pthread_mutexattr_destroy(&attr);
|
||||
if (0 != ret) {
|
||||
if( ret != 0 ) {
|
||||
fail("pthread_mutexattr_destroy()", ret);
|
||||
}
|
||||
|
||||
ret = pthread_cond_init(&cond->cond, 0);
|
||||
if (0 != ret) {
|
||||
if( ret != 0 ) {
|
||||
fail("pthread_cond_init()", ret);
|
||||
}
|
||||
|
||||
cond->ccount = 0lu;
|
||||
cond->wcount = 0lu;
|
||||
cond->ccount = 0;
|
||||
cond->wcount = 0;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
xdestroy(Cond *cond)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = pthread_cond_destroy(&cond->cond);
|
||||
if (0 != ret) {
|
||||
int ret = pthread_cond_destroy(&cond->cond);
|
||||
if( ret != 0 ) {
|
||||
fail("pthread_cond_destroy()", ret);
|
||||
}
|
||||
|
||||
ret = pthread_mutex_destroy(&cond->lock);
|
||||
if (0 != ret) {
|
||||
if( ret != 0 ) {
|
||||
fail("pthread_mutex_destroy()", ret);
|
||||
}
|
||||
}
|
||||
|
@ -641,10 +649,8 @@ xdestroy(Cond *cond)
|
|||
void
|
||||
xlock(Cond *cond)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = pthread_mutex_lock(&cond->lock);
|
||||
if (0 != ret) {
|
||||
int ret = pthread_mutex_lock(&cond->lock);
|
||||
if( ret != 0 ) {
|
||||
fail("pthread_mutex_lock()", ret);
|
||||
}
|
||||
}
|
||||
|
@ -661,10 +667,8 @@ xlock_pred(Cond *cond)
|
|||
void
|
||||
xunlock(Cond *cond)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = pthread_mutex_unlock(&cond->lock);
|
||||
if (0 != ret) {
|
||||
int ret = pthread_mutex_unlock(&cond->lock);
|
||||
if( ret != 0 ) {
|
||||
fail("pthread_mutex_unlock()", ret);
|
||||
}
|
||||
}
|
||||
|
@ -673,11 +677,9 @@ xunlock(Cond *cond)
|
|||
void
|
||||
xwait(Cond *cond)
|
||||
{
|
||||
int ret;
|
||||
|
||||
++cond->wcount;
|
||||
ret = pthread_cond_wait(&cond->cond, &cond->lock);
|
||||
if (0 != ret) {
|
||||
int ret = pthread_cond_wait(&cond->cond, &cond->lock);
|
||||
if( ret != 0 ) {
|
||||
fail("pthread_cond_wait()", ret);
|
||||
}
|
||||
++cond->ccount;
|
||||
|
@ -687,10 +689,8 @@ xwait(Cond *cond)
|
|||
void
|
||||
xsignal(Cond *cond)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = pthread_cond_signal(&cond->cond);
|
||||
if (0 != ret) {
|
||||
int ret = pthread_cond_signal(&cond->cond);
|
||||
if( ret != 0 ) {
|
||||
fail("pthread_cond_signal()", ret);
|
||||
}
|
||||
}
|
||||
|
@ -699,10 +699,8 @@ xsignal(Cond *cond)
|
|||
void
|
||||
xbroadcast(Cond *cond)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = pthread_cond_broadcast(&cond->cond);
|
||||
if (0 != ret) {
|
||||
int ret = pthread_cond_broadcast(&cond->cond);
|
||||
if( ret != 0 ) {
|
||||
fail("pthread_cond_broadcast()", ret);
|
||||
}
|
||||
}
|
||||
|
@ -711,10 +709,8 @@ xbroadcast(Cond *cond)
|
|||
void
|
||||
xcreate(pthread_t *thread, void *(*routine)(void *), void *arg)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = pthread_create(thread, 0, routine, arg);
|
||||
if (0 != ret) {
|
||||
int ret = pthread_create(thread, 0, routine, arg);
|
||||
if( ret != 0 ) {
|
||||
fail("pthread_create()", ret);
|
||||
}
|
||||
}
|
||||
|
@ -723,10 +719,8 @@ xcreate(pthread_t *thread, void *(*routine)(void *), void *arg)
|
|||
void
|
||||
xjoin(pthread_t thread)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = pthread_join(thread, 0);
|
||||
if (0 != ret) {
|
||||
int ret = pthread_join(thread, 0);
|
||||
if( ret != 0 ) {
|
||||
fail("pthread_join()", ret);
|
||||
}
|
||||
}
|
||||
|
@ -735,7 +729,7 @@ xjoin(pthread_t thread)
|
|||
void
|
||||
xraise(int sig)
|
||||
{
|
||||
if (-1 == kill(pid, sig)) {
|
||||
if( -1 == kill(pid, sig) ) {
|
||||
fail("kill()", errno);
|
||||
}
|
||||
}
|
||||
|
@ -743,59 +737,11 @@ xraise(int sig)
|
|||
|
||||
/* Private stuff part 2. */
|
||||
|
||||
struct Opts
|
||||
{
|
||||
unsigned num_worker; /* Start this many worker threads. */
|
||||
unsigned clidx; /* Compression level index in [0u .. 8u]. */
|
||||
int print_cctrs; /* Print condition variable counters. */
|
||||
};
|
||||
|
||||
/* Backlog factor for all workers together. */
|
||||
static const unsigned blf = 3u;
|
||||
|
||||
/* Separator characters in environment variable values. No escaping. */
|
||||
static const char envsep[] = " \t";
|
||||
|
||||
|
||||
static void *
|
||||
trace_malloc(size_t size)
|
||||
{
|
||||
void *ret;
|
||||
int save_errno = 0;
|
||||
|
||||
ret = malloc(size);
|
||||
if (0 == ret) {
|
||||
save_errno = errno;
|
||||
}
|
||||
|
||||
if (0 > fprintf(stderr, "%lu: malloc(%lu) == %p\n", (long unsigned)pid,
|
||||
(long unsigned)size, ret)
|
||||
) {
|
||||
fatal();
|
||||
}
|
||||
|
||||
if (0 == ret) {
|
||||
errno = save_errno;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
trace_free(void *ptr)
|
||||
{
|
||||
if (0 > fprintf(stderr, "%lu: free(%p)\n", (long unsigned)pid, ptr)) {
|
||||
fatal();
|
||||
}
|
||||
free(ptr);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
xsigemptyset(sigset_t *set)
|
||||
{
|
||||
if (-1 == sigemptyset(set)) {
|
||||
if( -1 == sigemptyset(set) ) {
|
||||
fail("sigemptyset()", errno);
|
||||
}
|
||||
}
|
||||
|
@ -804,7 +750,7 @@ xsigemptyset(sigset_t *set)
|
|||
static void
|
||||
xsigaddset(sigset_t *set, int signo)
|
||||
{
|
||||
if (-1 == sigaddset(set, signo)) {
|
||||
if( -1 == sigaddset(set, signo) ) {
|
||||
fail("sigaddset()", errno);
|
||||
}
|
||||
}
|
||||
|
@ -813,10 +759,8 @@ xsigaddset(sigset_t *set, int signo)
|
|||
static void
|
||||
xsigmask(int how, const sigset_t *set, sigset_t *oset)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = pthread_sigmask(how, set, oset);
|
||||
if (0 != ret) {
|
||||
int ret = pthread_sigmask(how, set, oset);
|
||||
if( ret != 0 ) {
|
||||
fail("pthread_sigmask()", ret);
|
||||
}
|
||||
}
|
||||
|
@ -831,54 +775,35 @@ xsigaction(int sig, void (*handler)(int))
|
|||
xsigemptyset(&act.sa_mask);
|
||||
act.sa_flags = 0;
|
||||
|
||||
if (-1 == sigaction(sig, &act, 0)) {
|
||||
if( -1 == sigaction(sig, &act, 0) ) {
|
||||
fail("sigaction()", errno);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
enum caught_sig
|
||||
{
|
||||
CS_INT = 1,
|
||||
CS_TERM,
|
||||
CS_USR1,
|
||||
CS_USR2
|
||||
};
|
||||
enum Caught_sig { CS_INT = 1, CS_TERM, CS_USR1, CS_USR2 };
|
||||
|
||||
static volatile sig_atomic_t caught_sig;
|
||||
|
||||
|
||||
static void
|
||||
sighandler(int sig)
|
||||
{
|
||||
extern "C" void sighandler( int sig )
|
||||
{
|
||||
/* sig_atomic_t is nowhere required to be able to hold signal values. */
|
||||
switch (sig) {
|
||||
case SIGINT:
|
||||
caught_sig = CS_INT;
|
||||
break;
|
||||
|
||||
case SIGTERM:
|
||||
caught_sig = CS_TERM;
|
||||
break;
|
||||
|
||||
case SIGUSR1:
|
||||
caught_sig = CS_USR1;
|
||||
break;
|
||||
|
||||
case SIGUSR2:
|
||||
caught_sig = CS_USR2;
|
||||
break;
|
||||
|
||||
default:
|
||||
assert(0);
|
||||
switch( sig )
|
||||
{
|
||||
case SIGINT : caught_sig = CS_INT; break;
|
||||
case SIGTERM: caught_sig = CS_TERM; break;
|
||||
case SIGUSR1: caught_sig = CS_USR1; break;
|
||||
case SIGUSR2: caught_sig = CS_USR2; break;
|
||||
default: internal_error( "caught signal not in set" );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
process( const Opts *opts, unsigned num_slot,
|
||||
int infd, int outfd, const Pretty_print & pp, const sigset_t *unblocked )
|
||||
{
|
||||
static void compress( const lzma_options & encoder_options, const int num_workers,
|
||||
int debug_level, int num_slots, int infd, int outfd,
|
||||
const Pretty_print & pp, const sigset_t *unblocked )
|
||||
{
|
||||
/*
|
||||
We could wait for signals with either sigwait() or sigsuspend(). SUSv2
|
||||
states about sigwait() that its effect on signal actions is unspecified.
|
||||
|
@ -896,18 +821,19 @@ process( const Opts *opts, unsigned num_slot,
|
|||
13-OCT-2009 lacos
|
||||
*/
|
||||
|
||||
Plzip_arg muxer_arg;
|
||||
pthread_t muxer;
|
||||
if( verbosity >= 1 ) pp();
|
||||
|
||||
if( verbosity >= 1 ) pp( "" );
|
||||
|
||||
muxer_arg.num_worker = opts->num_worker;
|
||||
muxer_arg.num_slot = num_slot;
|
||||
muxer_arg.clidx = opts->clidx;
|
||||
muxer_arg.print_cctrs = opts->print_cctrs;
|
||||
Muxer_arg muxer_arg;
|
||||
muxer_arg.dictionary_size = encoder_options.dictionary_size;
|
||||
muxer_arg.match_len_limit = encoder_options.match_len_limit;
|
||||
muxer_arg.num_workers = num_workers;
|
||||
muxer_arg.num_slots = num_slots;
|
||||
muxer_arg.debug_level = debug_level;
|
||||
muxer_arg.infd = infd;
|
||||
muxer_arg.outfd = outfd;
|
||||
xcreate(&muxer, plzip_wrap, &muxer_arg);
|
||||
|
||||
pthread_t muxer_thread;
|
||||
xcreate(&muxer_thread, muxer, &muxer_arg);
|
||||
|
||||
/* Unblock signals, wait for them, then block them again. */
|
||||
{
|
||||
|
@ -915,7 +841,7 @@ process( const Opts *opts, unsigned num_slot,
|
|||
assert(-1 == ret && EINTR == errno);
|
||||
}
|
||||
|
||||
switch (caught_sig) {
|
||||
switch( caught_sig ) {
|
||||
case CS_INT:
|
||||
case CS_TERM: // FIXME remove output file
|
||||
{
|
||||
|
@ -951,16 +877,16 @@ process( const Opts *opts, unsigned num_slot,
|
|||
assert(0);
|
||||
}
|
||||
|
||||
xjoin(muxer);
|
||||
}
|
||||
xjoin(muxer_thread);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
sigs_mod(int block_n_catch, sigset_t *oset)
|
||||
{
|
||||
{
|
||||
void (*handler)(int);
|
||||
|
||||
if (block_n_catch) {
|
||||
if( block_n_catch ) {
|
||||
sigset_t mask;
|
||||
|
||||
xsigemptyset(&mask);
|
||||
|
@ -981,33 +907,9 @@ sigs_mod(int block_n_catch, sigset_t *oset)
|
|||
xsigaction(SIGUSR1, handler);
|
||||
xsigaction(SIGUSR2, handler);
|
||||
|
||||
if (!block_n_catch) {
|
||||
if( !block_n_catch ) {
|
||||
xsigmask(SIG_SETMASK, oset, 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void show_error( const char * msg, const int errcode, const bool help ) throw()
|
||||
{
|
||||
if( verbosity >= 0 )
|
||||
{
|
||||
if( msg && msg[0] != 0 )
|
||||
{
|
||||
std::fprintf( stderr, "%s: %s", program_name, msg );
|
||||
if( errcode > 0 ) std::fprintf( stderr, ": %s", std::strerror( errcode ) );
|
||||
std::fprintf( stderr, "\n" );
|
||||
}
|
||||
if( help && invocation_name && invocation_name[0] != 0 )
|
||||
std::fprintf( stderr, "Try `%s --help' for more information.\n", invocation_name );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void internal_error( const char * msg )
|
||||
{
|
||||
std::string s( "internal error: " ); s += msg;
|
||||
show_error( s.c_str() );
|
||||
std::exit( 3 );
|
||||
}
|
||||
|
||||
|
||||
|
@ -1050,7 +952,6 @@ int writeblock( const int fd, const char * buf, const int size ) throw()
|
|||
|
||||
int main( const int argc, const char * argv[] )
|
||||
{
|
||||
Opts opts;
|
||||
// Mapping from gzip/bzip2 style 1..9 compression modes
|
||||
// to the corresponding LZMA compression modes.
|
||||
const lzma_options option_mapping[] =
|
||||
|
@ -1065,7 +966,9 @@ int main( const int argc, const char * argv[] )
|
|||
{ 1 << 24, 163 }, // -8
|
||||
{ 1 << 25, 273 } }; // -9
|
||||
lzma_options encoder_options = option_mapping[5]; // default = "-6"
|
||||
int debug_level = 0;
|
||||
int inhandle = -1;
|
||||
int num_workers = 0; // Start this many worker threads
|
||||
Mode program_mode = m_compress;
|
||||
bool force = false;
|
||||
bool keep_input_files = false;
|
||||
|
@ -1081,30 +984,15 @@ int main( const int argc, const char * argv[] )
|
|||
main_thread = pthread_self();
|
||||
pid = getpid();
|
||||
|
||||
mallocf = malloc;
|
||||
freef = free;
|
||||
|
||||
xsigaction(SIGPIPE, SIG_IGN);
|
||||
xsigaction(SIGXFSZ, SIG_IGN);
|
||||
|
||||
/* Effectuate option defaults. */
|
||||
long max_worker = sysconf(_SC_THREAD_THREADS_MAX);
|
||||
if (-1L == max_worker) {
|
||||
max_worker = LONG_MAX;
|
||||
}
|
||||
if (UINT_MAX < (long unsigned)max_worker) {
|
||||
max_worker = UINT_MAX;
|
||||
}
|
||||
if (UINT_MAX / blf < (unsigned)max_worker) {
|
||||
max_worker = UINT_MAX / blf;
|
||||
}
|
||||
if ((size_t)-1 / sizeof(pthread_t) < (unsigned)max_worker) {
|
||||
max_worker = (size_t)-1 / sizeof(pthread_t);
|
||||
}
|
||||
|
||||
opts.num_worker = 0u;
|
||||
opts.clidx = 5u;
|
||||
opts.print_cctrs = 0;
|
||||
const int slots_per_worker = 2;
|
||||
long max_workers = sysconf( _SC_THREAD_THREADS_MAX );
|
||||
if( max_workers < 1 || max_workers > INT_MAX / slots_per_worker )
|
||||
max_workers = INT_MAX / slots_per_worker;
|
||||
if( max_workers > INT_MAX / (int)sizeof( pthread_t ) )
|
||||
max_workers = INT_MAX / sizeof( pthread_t );
|
||||
|
||||
const Arg_parser::Option options[] =
|
||||
{
|
||||
|
@ -1150,25 +1038,24 @@ int main( const int argc, const char * argv[] )
|
|||
case '1': case '2': case '3':
|
||||
case '4': case '5': case '6':
|
||||
case '7': case '8': case '9':
|
||||
opts.clidx = code - '1';
|
||||
encoder_options = option_mapping[code-'1']; break;
|
||||
case 'b': break;
|
||||
case 'c': to_stdout = true; break;
|
||||
case 'd': program_mode = m_decompress; break;
|
||||
case 'D': { int debug_level = getnum( arg, 0, 0, 3 );
|
||||
if( debug_level & 1 ) opts.print_cctrs = 1;
|
||||
if( debug_level & 2 )
|
||||
{ mallocf = trace_malloc; freef = trace_free; } }
|
||||
case 'D': debug_level = getnum( arg, 0, 0, 3 );
|
||||
break;
|
||||
case 'f': force = true; break;
|
||||
case 'h': show_help(); return 0;
|
||||
case 'k': keep_input_files = true; break;
|
||||
case 'm': encoder_options.match_len_limit =
|
||||
getnum( arg, 0, 5, 273 ); break;
|
||||
getnum( arg, 0, LZ_min_match_len_limit(),
|
||||
LZ_max_match_len_limit() ); break;
|
||||
case 'o': default_output_filename = arg; break;
|
||||
case 'n': opts.num_worker = getnum( arg, 0, 1, max_worker ); break;
|
||||
case 'n': num_workers = getnum( arg, 0, 1, max_workers ); break;
|
||||
case 'q': verbosity = -1; break;
|
||||
case 's': encoder_options.dictionary_size = get_dict_size( arg );
|
||||
break;
|
||||
case 'S': break;
|
||||
case 't': program_mode = m_test; break;
|
||||
case 'v': if( verbosity < 4 ) ++verbosity; break;
|
||||
case 'V': show_version(); return 0;
|
||||
|
@ -1176,23 +1063,13 @@ int main( const int argc, const char * argv[] )
|
|||
}
|
||||
}
|
||||
|
||||
if( opts.num_worker <= 0 )
|
||||
if( num_workers <= 0 )
|
||||
{
|
||||
#ifdef _SC_NPROCESSORS_ONLN
|
||||
long num_online = sysconf( _SC_NPROCESSORS_ONLN );
|
||||
if( num_online <= 0 )
|
||||
{
|
||||
show_error( "number of online processors unavailable.", 0, true );
|
||||
fatal();
|
||||
}
|
||||
opts.num_worker = std::min( num_online, max_worker );
|
||||
#else
|
||||
show_error( "number of (de)compression threads not set.", 0, true );
|
||||
fatal();
|
||||
#endif
|
||||
if( num_online <= 0 ) num_online = 2;
|
||||
num_workers = std::min( num_online, max_workers );
|
||||
}
|
||||
assert(UINT_MAX / blf >= opts.num_worker);
|
||||
unsigned num_slot = opts.num_worker * blf;
|
||||
const int num_slots = num_workers * slots_per_worker;
|
||||
|
||||
bool filenames_given = false;
|
||||
for( ; argind < parser.arguments(); ++argind )
|
||||
|
@ -1265,14 +1142,14 @@ int main( const int argc, const char * argv[] )
|
|||
|
||||
if( output_filename.size() && !to_stdout && program_mode != m_test )
|
||||
delete_output_on_interrupt = true;
|
||||
const struct stat * in_statsp = input_filename.size() ? &in_stats : 0;
|
||||
const struct stat * const in_statsp = input_filename.size() ? &in_stats : 0;
|
||||
pp.set_name( input_filename );
|
||||
int tmp = 0;
|
||||
if( program_mode == m_compress )
|
||||
{
|
||||
sigset_t unblocked;
|
||||
sigs_mod(1, &unblocked);
|
||||
process( &opts, num_slot, inhandle, outhandle, pp, &unblocked );
|
||||
compress( encoder_options, num_workers, debug_level, num_slots, inhandle, outhandle, pp, &unblocked );
|
||||
sigs_mod(0, &unblocked);
|
||||
}
|
||||
else
|
||||
|
@ -1281,7 +1158,7 @@ int main( const int argc, const char * argv[] )
|
|||
if( tmp && program_mode != m_test ) cleanup_and_fail( retval );
|
||||
|
||||
if( delete_output_on_interrupt )
|
||||
close_and_set_permissions( in_statsp, &retval );
|
||||
close_and_set_permissions( in_statsp );
|
||||
if( input_filename.size() )
|
||||
{
|
||||
close( inhandle ); inhandle = -1;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue