summaryrefslogtreecommitdiffstats
path: root/main.cc
diff options
context:
space:
mode:
Diffstat (limited to 'main.cc')
-rw-r--r--main.cc445
1 files changed, 51 insertions, 394 deletions
diff --git a/main.cc b/main.cc
index 18ed642..f3f12e0 100644
--- a/main.cc
+++ b/main.cc
@@ -25,20 +25,17 @@
#define _FILE_OFFSET_BITS 64
#include <algorithm>
-#include <cassert>
#include <cerrno>
#include <climits>
#include <csignal>
-#include <cstdarg>
-#include <cstddef>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <string>
#include <vector>
#include <fcntl.h>
-#include <stdint.h>
#include <pthread.h>
+#include <stdint.h>
#include <unistd.h>
#include <utime.h>
#include <sys/stat.h>
@@ -49,7 +46,6 @@
#endif
#include "arg_parser.h"
-#include "main.h"
#include "plzip.h"
#ifndef LLONG_MAX
@@ -72,6 +68,12 @@ const char * const Program_name = "Plzip";
const char * const program_name = "plzip";
const char * const program_year = "2010";
+#ifdef O_BINARY
+const int o_binary = O_BINARY;
+#else
+const int o_binary = 0;
+#endif
+
struct { const char * from; const char * to; } const known_extensions[] = {
{ ".lz", "" },
{ ".tlz", ".tar" },
@@ -88,6 +90,8 @@ enum Mode { m_compress = 0, m_decompress, m_test };
std::string output_filename;
int outhandle = -1;
bool delete_output_on_interrupt = false;
+pthread_t main_thread;
+pid_t main_thread_pid;
class Pretty_print
{
@@ -132,6 +136,7 @@ void show_help() throw()
std::printf( " -h, --help display this help and exit\n" );
std::printf( " -V, --version output version information and exit\n" );
// std::printf( " -b, --member-size=<n> set member size limit in bytes\n" );
+ std::printf( " -B, --data-size=<n> set input data block size 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" );
@@ -267,7 +272,7 @@ int open_instream( const std::string & name, struct stat * in_statsp,
}
else
{
- inhandle = open( name.c_str(), O_RDONLY );
+ inhandle = open( name.c_str(), O_RDONLY | o_binary );
if( inhandle < 0 )
{
if( verbosity >= 0 )
@@ -324,9 +329,11 @@ void set_d_outname( const std::string & name, const int i ) throw()
bool open_outstream( const bool force ) throw()
{
if( force )
- outhandle = open( output_filename.c_str(), O_CREAT | O_TRUNC | O_WRONLY,
+ outhandle = open( output_filename.c_str(),
+ O_CREAT | O_TRUNC | O_WRONLY | o_binary,
S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH );
- else outhandle = open( output_filename.c_str(), O_CREAT | O_EXCL | O_WRONLY,
+ else outhandle = open( output_filename.c_str(),
+ O_CREAT | O_EXCL | O_WRONLY | o_binary,
S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH );
if( outhandle < 0 )
{
@@ -412,14 +419,13 @@ int do_decompress( LZ_Decoder * const decoder, const int inhandle,
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];
- if( verbosity >= 1 ) pp();
while( true )
{
int in_size = std::min( LZ_decompress_write_size( decoder ), in_buffer_size );
if( in_size > 0 )
{
const int max_in_size = in_size;
- in_size = readblock( inhandle, (char *)in_buffer, max_in_size );
+ in_size = readblock( inhandle, 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 );
@@ -458,7 +464,7 @@ int do_decompress( LZ_Decoder * const decoder, const int inhandle,
}
else if( out_size > 0 && outhandle >= 0 )
{
- const int wr = writeblock( outhandle, (char *)out_buffer, out_size );
+ const int wr = writeblock( outhandle, out_buffer, out_size );
if( wr != out_size )
{ pp(); show_error( "write error", errno ); return 1; }
}
@@ -490,9 +496,12 @@ int decompress( const int inhandle, const Pretty_print & pp,
}
-extern "C" void signal_handler( int ) throw()
+extern "C" void signal_handler( int sig ) throw()
{
- show_error( "Control-C or similar caught, quitting." );
+ if( !pthread_equal( pthread_self(), main_thread ) )
+ kill( main_thread_pid, sig );
+ if( sig != SIGUSR1 )
+ show_error( "Control-C or similar caught, quitting." );
cleanup_and_fail( 1 );
}
@@ -502,6 +511,7 @@ void set_signals() throw()
signal( SIGHUP, signal_handler );
signal( SIGINT, signal_handler );
signal( SIGTERM, signal_handler );
+ signal( SIGUSR1, signal_handler );
}
} // end namespace
@@ -551,372 +561,16 @@ void internal_error( const char * msg )
}
-/* Private stuff needed by fatal(). */
-static pthread_t main_thread;
-
-static pid_t pid;
-
-
-/* Public utility variables and functions. */
-
-/*
- 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()
-{
- if( pthread_equal(pthread_self(), main_thread) )
- cleanup_and_fail( 1 );
- else
- {
- if( 0 == kill(pid, SIGUSR1) )
- pthread_exit(0);
- }
- _exit( 1 );
-}
-
-
-void
-fail(const char *fmt, int err, ...)
-{
- va_list args;
-
- /* Locking stderr should also protect strerror(). */
- flockfile(stderr);
- (void)fprintf(stderr, "%s: ", program_name);
-
- va_start(args, err);
- (void)vfprintf(stderr, fmt, args);
- va_end(args);
-
- (void)fprintf(stderr, ": %s\n", strerror(err));
- funlockfile(stderr);
- /* Stream stderr is never fully buffered originally. */
- fatal();
-}
-
-
-void
-xinit(Cond *cond)
-{
- pthread_mutexattr_t attr;
-
- int ret = pthread_mutexattr_init(&attr);
- if( ret != 0 ) {
- fail("pthread_mutexattr_init()", ret);
- }
-
- ret = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK);
- if( ret != 0 ) {
- fail("pthread_mutexattr_settype()", ret);
- }
-
- ret = pthread_mutex_init(&cond->lock, &attr);
- if( ret != 0 ) {
- fail("pthread_mutex_init()", ret);
- }
-
- ret = pthread_mutexattr_destroy(&attr);
- if( ret != 0 ) {
- fail("pthread_mutexattr_destroy()", ret);
- }
-
- ret = pthread_cond_init(&cond->cond, 0);
- if( ret != 0 ) {
- fail("pthread_cond_init()", ret);
- }
-
- cond->ccount = 0;
- cond->wcount = 0;
-}
-
-
-void
-xdestroy(Cond *cond)
-{
- int ret = pthread_cond_destroy(&cond->cond);
- if( ret != 0 ) {
- fail("pthread_cond_destroy()", ret);
- }
-
- ret = pthread_mutex_destroy(&cond->lock);
- if( ret != 0 ) {
- fail("pthread_mutex_destroy()", ret);
- }
-}
-
-
-void
-xlock(Cond *cond)
-{
- int ret = pthread_mutex_lock(&cond->lock);
- if( ret != 0 ) {
- fail("pthread_mutex_lock()", ret);
- }
-}
-
-
-void
-xlock_pred(Cond *cond)
-{
- xlock(cond);
- ++cond->ccount;
-}
-
-
-void
-xunlock(Cond *cond)
-{
- int ret = pthread_mutex_unlock(&cond->lock);
- if( ret != 0 ) {
- fail("pthread_mutex_unlock()", ret);
- }
-}
-
-
-void
-xwait(Cond *cond)
-{
- ++cond->wcount;
- int ret = pthread_cond_wait(&cond->cond, &cond->lock);
- if( ret != 0 ) {
- fail("pthread_cond_wait()", ret);
- }
- ++cond->ccount;
-}
-
-
-void
-xsignal(Cond *cond)
-{
- int ret = pthread_cond_signal(&cond->cond);
- if( ret != 0 ) {
- fail("pthread_cond_signal()", ret);
- }
-}
-
-
-void
-xbroadcast(Cond *cond)
-{
- int ret = pthread_cond_broadcast(&cond->cond);
- if( ret != 0 ) {
- fail("pthread_cond_broadcast()", ret);
- }
-}
-
-
-void
-xcreate(pthread_t *thread, void *(*routine)(void *), void *arg)
-{
- int ret = pthread_create(thread, 0, routine, arg);
- if( ret != 0 ) {
- fail("pthread_create()", ret);
- }
-}
-
-
-void
-xjoin(pthread_t thread)
-{
- int ret = pthread_join(thread, 0);
- if( ret != 0 ) {
- fail("pthread_join()", ret);
- }
-}
-
-
-void
-xraise(int sig)
-{
- if( -1 == kill(pid, sig) ) {
- fail("kill()", errno);
- }
-}
-
-
-/* Private stuff part 2. */
-
-
-static void
-xsigemptyset(sigset_t *set)
-{
- if( -1 == sigemptyset(set) ) {
- fail("sigemptyset()", errno);
- }
-}
-
-
-static void
-xsigaddset(sigset_t *set, int signo)
-{
- if( -1 == sigaddset(set, signo) ) {
- fail("sigaddset()", errno);
- }
-}
-
-
-static void
-xsigmask(int how, const sigset_t *set, sigset_t *oset)
-{
- int ret = pthread_sigmask(how, set, oset);
- if( ret != 0 ) {
- fail("pthread_sigmask()", ret);
- }
-}
-
-
-static void
-xsigaction(int sig, void (*handler)(int))
-{
- struct sigaction act;
-
- act.sa_handler = handler;
- xsigemptyset(&act.sa_mask);
- act.sa_flags = 0;
-
- if( -1 == sigaction(sig, &act, 0) ) {
- fail("sigaction()", errno);
- }
-}
-
-
-enum Caught_sig { CS_INT = 1, CS_TERM, CS_USR1, CS_USR2 };
-
-static volatile sig_atomic_t caught_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: internal_error( "caught signal not in set" );
- }
- }
-
-
-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.
- SUSv3 still claims the same.
-
- The SUSv2 description of sigsuspend() talks about both the thread and the
- whole process being suspended until a signal arrives, although thread
- suspension seems much more likely from the wording. They note that they
- filed a clarification request for this. SUSv3 cleans this up and chooses
- thread suspension which was more logical anyway.
-
- I favor sigsuspend() because I need to re-raise SIGTERM and SIGINT, and
- unspecified action behavior with sigwait() seems messy.
-
- 13-OCT-2009 lacos
- */
-
- if( verbosity >= 1 ) pp();
-
- 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;
-
- pthread_t muxer_thread;
- xcreate(&muxer_thread, muxer, &muxer_arg);
-
- /* Unblock signals, wait for them, then block them again. */
- {
- int ret = sigsuspend(unblocked);
- assert(-1 == ret && EINTR == errno);
- }
-
- switch( caught_sig ) {
- case CS_INT:
- case CS_TERM: // FIXME remove output file
- {
- int sig;
- sigset_t mask;
-
- sig = (CS_INT == caught_sig) ? SIGINT : SIGTERM;
- /*
- We might have inherited a SIG_IGN from the parent, but that would
- make no sense here. 24-OCT-2009 lacos
- */
- xsigaction(sig, SIG_DFL);
- xraise(sig);
-
- xsigemptyset(&mask);
- xsigaddset(&mask, sig);
- xsigmask(SIG_UNBLOCK, &mask, 0);
- }
- /*
- We shouldn't reach this point, but if we do for some reason, fall
- through.
- */
-
- case CS_USR1:
- /* Error from a non-main thread via fatal(). */
- fatal();
-
- case CS_USR2:
- /* Muxer thread joined other sub-threads and finished successfully. */
- break;
-
- default:
- assert(0);
- }
-
- xjoin(muxer_thread);
- }
-
-
-static void
-sigs_mod(int block_n_catch, sigset_t *oset)
- {
- void (*handler)(int);
-
- if( block_n_catch ) {
- sigset_t mask;
-
- xsigemptyset(&mask);
- xsigaddset(&mask, SIGINT);
- xsigaddset(&mask, SIGTERM);
- xsigaddset(&mask, SIGUSR1);
- xsigaddset(&mask, SIGUSR2);
- xsigmask(SIG_BLOCK, &mask, oset);
-
- handler = sighandler;
- }
- else {
- handler = SIG_DFL;
- }
-
- xsigaction(SIGINT, handler);
- xsigaction(SIGTERM, handler);
- xsigaction(SIGUSR1, handler);
- xsigaction(SIGUSR2, handler);
-
- if( !block_n_catch ) {
- xsigmask(SIG_SETMASK, oset, 0);
- }
- }
+// 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() { signal_handler( SIGUSR1 ); }
// Returns the number of bytes really read.
// If (returned value < size) and (errno == 0), means EOF was reached.
//
-int readblock( const int fd, char * buf, const int size ) throw()
+int readblock( const int fd, uint8_t * buf, const int size ) throw()
{
int rest = size;
errno = 0;
@@ -935,7 +589,7 @@ int readblock( const int fd, char * buf, const int size ) throw()
// Returns the number of bytes really written.
// If (returned value < size), it is always an error.
//
-int writeblock( const int fd, const char * buf, const int size ) throw()
+int writeblock( const int fd, const uint8_t * buf, const int size ) throw()
{
int rest = size;
errno = 0;
@@ -966,6 +620,7 @@ 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 data_size = 0;
int debug_level = 0;
int inhandle = -1;
int num_workers = 0; // Start this many worker threads
@@ -977,22 +632,18 @@ int main( const int argc, const char * argv[] )
std::string default_output_filename;
std::vector< std::string > filenames;
invocation_name = argv[0];
+ main_thread = pthread_self();
+ main_thread_pid = getpid();
if( LZ_version()[0] != LZ_version_string[0] )
internal_error( "bad library version" );
- main_thread = pthread_self();
- pid = getpid();
-
- xsigaction(SIGPIPE, SIG_IGN);
- xsigaction(SIGXFSZ, SIG_IGN);
-
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 );
+ if( max_workers > INT_MAX / (int)sizeof (pthread_t) )
+ max_workers = INT_MAX / sizeof (pthread_t);
const Arg_parser::Option options[] =
{
@@ -1006,6 +657,7 @@ int main( const int argc, const char * argv[] )
{ '8', 0, Arg_parser::no },
{ '9', "best", Arg_parser::no },
{ 'b', "member-size", Arg_parser::yes },
+ { 'B', "data-size", Arg_parser::yes },
{ 'c', "stdout", Arg_parser::no },
{ 'd', "decompress", Arg_parser::no },
{ 'D', "debug", Arg_parser::yes },
@@ -1040,6 +692,8 @@ int main( const int argc, const char * argv[] )
case '7': case '8': case '9':
encoder_options = option_mapping[code-'1']; break;
case 'b': break;
+ case 'B': data_size = getnum( arg, 0, 100000,
+ 2 * LZ_max_dictionary_size() ); break;
case 'c': to_stdout = true; break;
case 'd': program_mode = m_decompress; break;
case 'D': debug_level = getnum( arg, 0, 0, 3 );
@@ -1048,8 +702,8 @@ int main( const int argc, const char * argv[] )
case 'h': show_help(); return 0;
case 'k': keep_input_files = true; break;
case 'm': encoder_options.match_len_limit =
- getnum( arg, 0, LZ_min_match_len_limit(),
- LZ_max_match_len_limit() ); break;
+ getnum( arg, 0, LZ_min_match_len_limit(),
+ LZ_max_match_len_limit() ); break;
case 'o': default_output_filename = arg; break;
case 'n': num_workers = getnum( arg, 0, 1, max_workers ); break;
case 'q': verbosity = -1; break;
@@ -1063,13 +717,16 @@ int main( const int argc, const char * argv[] )
}
}
+ if( data_size <= 0 )
+ data_size = 2 * std::max( 65536, encoder_options.dictionary_size );
+
if( num_workers <= 0 )
{
long num_online = sysconf( _SC_NPROCESSORS_ONLN );
- if( num_online <= 0 ) num_online = 2;
+ if( num_online <= 0 ) num_online = 1;
num_workers = std::min( num_online, max_workers );
}
- const int num_slots = num_workers * slots_per_worker;
+ const int num_slots = std::max( 1, ( num_workers * slots_per_worker ) - 1 );
bool filenames_given = false;
for( ; argind < parser.arguments(); ++argind )
@@ -1079,7 +736,9 @@ int main( const int argc, const char * argv[] )
}
if( filenames.empty() ) filenames.push_back("-");
- if( filenames_given && program_mode != m_compress ) set_signals();
+ if( !to_stdout && program_mode != m_test &&
+ ( filenames_given || default_output_filename.size() ) )
+ set_signals();
Pretty_print pp( filenames );
if( program_mode == m_test )
@@ -1144,14 +803,12 @@ int main( const int argc, const char * argv[] )
delete_output_on_interrupt = true;
const struct stat * const in_statsp = input_filename.size() ? &in_stats : 0;
pp.set_name( input_filename );
+ if( verbosity >= 1 ) pp();
int tmp = 0;
if( program_mode == m_compress )
- {
- sigset_t unblocked;
- sigs_mod(1, &unblocked);
- compress( encoder_options, num_workers, debug_level, num_slots, inhandle, outhandle, pp, &unblocked );
- sigs_mod(0, &unblocked);
- }
+ tmp = compress( data_size, encoder_options.dictionary_size,
+ encoder_options.match_len_limit, num_workers,
+ num_slots, inhandle, outhandle, debug_level );
else
tmp = decompress( inhandle, pp, program_mode == m_test );
if( tmp > retval ) retval = tmp;