/* Tarlz - Archiver with multimember lzip compression Copyright (C) 2013-2024 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 the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #define _FILE_OFFSET_BITS 64 #include #include "tarlz.h" #include "common_mutex.h" namespace { int error_status = 0; } // end namespace void xinit_mutex( pthread_mutex_t * const mutex ) { const int errcode = pthread_mutex_init( mutex, 0 ); if( errcode ) { show_error( "pthread_mutex_init", errcode ); exit_fail_mt(); } } void xinit_cond( pthread_cond_t * const cond ) { const int errcode = pthread_cond_init( cond, 0 ); if( errcode ) { show_error( "pthread_cond_init", errcode ); exit_fail_mt(); } } void xdestroy_mutex( pthread_mutex_t * const mutex ) { const int errcode = pthread_mutex_destroy( mutex ); if( errcode ) { show_error( "pthread_mutex_destroy", errcode ); exit_fail_mt(); } } void xdestroy_cond( pthread_cond_t * const cond ) { const int errcode = pthread_cond_destroy( cond ); if( errcode ) { show_error( "pthread_cond_destroy", errcode ); exit_fail_mt(); } } void xlock( pthread_mutex_t * const mutex ) { const int errcode = pthread_mutex_lock( mutex ); if( errcode ) { show_error( "pthread_mutex_lock", errcode ); exit_fail_mt(); } } void xunlock( pthread_mutex_t * const mutex ) { const int errcode = pthread_mutex_unlock( mutex ); if( errcode ) { show_error( "pthread_mutex_unlock", errcode ); exit_fail_mt(); } } void xwait( pthread_cond_t * const cond, pthread_mutex_t * const mutex ) { const int errcode = pthread_cond_wait( cond, mutex ); if( errcode ) { show_error( "pthread_cond_wait", errcode ); exit_fail_mt(); } } void xsignal( pthread_cond_t * const cond ) { const int errcode = pthread_cond_signal( cond ); if( errcode ) { show_error( "pthread_cond_signal", errcode ); exit_fail_mt(); } } void xbroadcast( pthread_cond_t * const cond ) { const int errcode = pthread_cond_broadcast( cond ); if( errcode ) { show_error( "pthread_cond_broadcast", errcode ); exit_fail_mt(); } } /* This can be called from any thread, main thread or sub-threads alike, since they all call common helper functions that call exit_fail_mt() in case of an error. */ void exit_fail_mt( const int retval ) { // calling 'exit' more than once results in undefined behavior static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; pthread_mutex_lock( &mutex ); // ignore errors to avoid loop std::exit( retval ); } /* If msgp is null, print the message, else return the message in *msgp. If prefix is already in the list, print nothing or return empty *msgp. Return true if a message is printed or returned in *msgp. */ bool print_removed_prefix( const std::string & prefix, std::string * const msgp ) { // prevent two threads from modifying the list of prefixes at the same time static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; static std::vector< std::string > prefixes; // list of prefixes if( verbosity < 0 || prefix.empty() ) { if( msgp ) msgp->clear(); return false; } xlock( &mutex ); for( unsigned i = 0; i < prefixes.size(); ++i ) if( prefixes[i] == prefix ) { xunlock( &mutex ); if( msgp ) msgp->clear(); return false; } prefixes.push_back( prefix ); std::string msg( "Removing leading '" ); msg += prefix; msg += "' from member names."; if( msgp ) *msgp = msg; else show_error( msg.c_str() ); xunlock( &mutex ); // put here to prevent mixing calls to show_error return true; } void set_error_status( const int retval ) { // prevent two threads from modifying the error_status at the same time static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; xlock( &mutex ); if( error_status < retval ) error_status = retval; xunlock( &mutex ); } int final_exit_status( int retval, const bool show_msg ) { if( retval == 0 && error_status ) { if( show_msg ) show_error( "Exiting with failure status due to previous errors." ); retval = error_status; } return retval; }