Merge branch 'storageareas' of github.com:connortechnology/ZoneMinder into storageareas

This commit is contained in:
Isaac Connor 2018-04-24 09:40:39 -07:00
commit ad376fc267
9 changed files with 114 additions and 142 deletions

View File

@ -147,7 +147,7 @@ our $mem_data = {
last_write_index => { type=>'uint32', seq=>$mem_seq++ },
last_read_index => { type=>'uint32', seq=>$mem_seq++ },
state => { type=>'uint32', seq=>$mem_seq++ },
last_event => { type=>'uint32', seq=>$mem_seq++ },
last_event => { type=>'uint64', seq=>$mem_seq++ },
action => { type=>'uint32', seq=>$mem_seq++ },
brightness => { type=>'int32', seq=>$mem_seq++ },
hue => { type=>'int32', seq=>$mem_seq++ },
@ -167,7 +167,6 @@ our $mem_data = {
last_read_time => { type=>'time_t64', seq=>$mem_seq++ },
control_state => { type=>'uint8[256]', seq=>$mem_seq++ },
alarm_cause => { type=>'int8[256]', seq=>$mem_seq++ },
}
},
trigger_data => { type=>'TriggerData', seq=>$mem_seq++, 'contents'=> {

View File

@ -240,11 +240,11 @@ use Sys::MemInfo qw(totalmem freemem totalswap freeswap);
use ZoneMinder::Server qw(CpuLoad);
#use Data::Dumper;
# We count 10 of these, so total timeout is this value *10.
use constant KILL_DELAY => 10; # seconds
use constant KILL_DELAY => 60; # seconds to wait between sending TERM and sending KILL
our %cmd_hash;
our %pid_hash;
our %terminating_processes;
sub run {
my $fd = 0;
@ -268,6 +268,7 @@ sub run {
Error( "Can't open pid file at " . ZM_PID );
}
# Tell any existing processes to die, wait 1 second between TERM and KILL
killAll( 1 );
dPrint( ZoneMinder::Logger::INFO, 'Socket should be open at ' .main::SOCK_FILE );
@ -303,7 +304,6 @@ sub run {
if ( ! ( $secs_count % 60 ) ) {
$dbh = zmDbConnect() if ! $dbh->ping();
my @cpuload = CpuLoad();
dPrint( ZoneMinder::Logger::DEBUG, 'Updating Server record' );
if ( ! defined $dbh->do(q{UPDATE Servers SET Status=?,CpuLoad=?,TotalMem=?,FreeMem=?,TotalSwap=?,FreeSwap=? WHERE Id=?}, undef,
'Running', $cpuload[0], &totalmem, &freemem, &totalswap, &freeswap, $Config{ZM_SERVER_ID} ) ) {
Error("Failed Updating status of Server record for Id=$Config{ZM_SERVER_ID}".$dbh->errstr());
@ -366,7 +366,10 @@ sub run {
#print( "Select timed out\n" );
restartPending();
}
}
check_for_processes_to_kill();
} # end while
dPrint( ZoneMinder::Logger::INFO, 'Server exiting at '
.strftime( '%y/%m/%d %H:%M:%S', localtime() )
."\n"
@ -515,44 +518,33 @@ sub send_stop {
."\n"
);
$process->{keepalive} = !$final;
$process->{term_sent_at} = time;
$process->{pending} = 0;
$terminating_processes{$command} = $process;
kill( 'TERM', $pid );
return $pid;
} # end sub send_stop
sub kill_until_dead {
my ( $process ) = @_;
# Now check it has actually gone away, if not kill -9 it
my $count = 0;
sub check_for_processes_to_kill {
# Turn off SIGCHLD
my $sigset = POSIX::SigSet->new;
my $blockset = POSIX::SigSet->new(SIGCHLD);
sigprocmask(SIG_BLOCK, $blockset, $sigset ) or die "dying at block...\n";
while( $process and $$process{pid} and kill( 0, $$process{pid} ) ) {
if ( $count++ > 10 ) {
foreach my $command ( %terminating_processes ) {
my $process = $cmd_hash{$command};
if ( $$process{term_sent_at} - time > KILL_DELAY ) {
dPrint(ZoneMinder::Logger::WARNING, "'$$process{command}' has not stopped at "
.strftime('%y/%m/%d %H:%M:%S', localtime())
.' after ' . ( KILL_DELAY * $count ) . ' seconds.'
." Sending KILL to pid $$process{pid}\n"
);
kill( 'KILL', $$process{pid} );
last;
.strftime('%y/%m/%d %H:%M:%S', localtime())
.' after ' . KILL_DELAY . ' seconds.'
." Sending KILL to pid $$process{pid}\n"
);
kill('KILL', $$process{pid});
}
# THe purpose of the signal blocking is to simplify the concurrency
sigprocmask(SIG_UNBLOCK, $blockset) or die "dying at unblock...\n";
sleep( KILL_DELAY );
sigprocmask(SIG_BLOCK, $blockset, $sigset ) or die "dying at block...\n";
}
sigprocmask(SIG_UNBLOCK, $blockset) or die "dying at unblock...\n";
}
sub _stop {
my ($final, $process ) = @_;
my $pid = send_stop( $final, $process );
return if ! $pid;
delete( $cmd_hash{$$process{command}} );
kill_until_dead( $process );
}
} # end sub check_for_processess_to_kill
sub stop {
my ( $daemon, @args ) = @_;
@ -560,57 +552,49 @@ sub stop {
my $process = $cmd_hash{$command};
if ( !$process ) {
dPrint( ZoneMinder::Logger::WARNING, "Can't find process with command of '$command'\n" );
return();
return;
}
_stop( 1, $process );
send_stop( 1, $process );
}
# restart is the same as stop, except that we flag the processes for restarting once it dies
# One difference is that if we don't know about the process, then we start it.
sub restart {
my $daemon = shift;
my @args = @_;
my ( $daemon, @args ) = @_;
my $command = $daemon;
$command .= ' '.join( ' ', ( @args ) ) if @args;
dPrint ( ZoneMinder::Logger::DEBUG, "Restarting $command\n");
my $command = join(' ', $daemon, @args );
dPrint(ZoneMinder::Logger::DEBUG, "Restarting $command\n");
my $process = $cmd_hash{$command};
if ( $process ) {
dPrint( ZoneMinder::Logger::DEBUG, "Have process" );
if ( $process->{pid} ) {
dPrint( ZoneMinder::Logger::DEBUG, "Have process pid " .$process->{pid} );
my $cpid = $process->{pid};
if ( defined($pid_hash{$cpid}) ) {
dPrint( ZoneMinder::Logger::DEBUG, "Have process pid hash " .$process->{pid} );
_stop( 0, $process );
return;
} else {
dPrint( ZoneMinder::Logger::DEBUG, "Not sending stop" );
}
}
if ( !$process ) {
dPrint(ZoneMinder::Logger::WARNING, "Can't find process with command of '$command'\n");
start($daemon, @args);
return;
}
start( $daemon, @args );
# Start will be handled by the reaper
send_stop(0, $process);
return;
}
sub reload {
my $daemon = shift;
my @args = @_;
my $command = $daemon;
$command .= ' '.join( ' ', ( @args ) ) if ( @args );
my $command = join(' ', $daemon, @args ) ;
my $process = $cmd_hash{$command};
if ( $process ) {
if ( $process->{pid} ) {
kill( 'HUP', $process->{pid} );
kill('HUP', $process->{pid});
}
}
}
sub logrot {
logReinit();
foreach my $process ( values( %pid_hash ) ) {
foreach my $process ( values(%pid_hash) ) {
if ( $process->{pid} ) {
# && $process->{command} =~ /^zm.*\.pl/ ) {
kill( 'HUP', $process->{pid} );
kill('HUP', $process->{pid});
}
}
}
@ -621,16 +605,18 @@ sub reaper {
my $status = $?;
my $process = $pid_hash{$cpid};
delete( $pid_hash{$cpid} );
delete $pid_hash{$cpid};
if ( !$process ) {
dPrint( ZoneMinder::Logger::INFO, "Can't find child with pid of '$cpid'\n" );
next;
}
delete $terminating_processes{$$process{command}};
delete $$process{term_sent_at};
$process->{stopped} = time();
$process->{runtime} = ($process->{stopped}-$process->{started});
delete( $process->{pid} );
delete $process->{pid};
my $exit_status = $status>>8;
my $exit_signal = $status&0xfe;
@ -677,6 +663,8 @@ sub reaper {
$process->{delay} = $Config{ZM_MAX_RESTART_DELAY};
}
}
} else {
delete $cmd_hash{$$process{command}};
}
}
$SIG{CHLD} = \&reaper;
@ -687,8 +675,8 @@ sub restartPending {
# Restart any pending processes
foreach my $process ( values( %cmd_hash ) ) {
if ( $process->{pending} && $process->{pending} <= time() ) {
dPrint( ZoneMinder::Logger::INFO, "Starting pending process, $process->{command}\n" );
start( $process->{daemon}, @{$process->{args}} );
dPrint(ZoneMinder::Logger::INFO, "Starting pending process, $process->{command}\n");
start($process->{daemon}, @{$process->{args}});
}
}
}
@ -699,21 +687,12 @@ sub shutdownAll {
next if ! $pid_hash{$pid};
send_stop( 1, $pid_hash{$pid} );
}
foreach my $pid ( keys %pid_hash ) {
# This is a quick fix because a SIGCHLD can happen and alter pid_hash while we are in here.
next if ! $pid_hash{$pid};
my $process = $pid_hash{$pid};
kill_until_dead( $process );
delete( $cmd_hash{$$process{command}} );
delete( $pid_hash{$pid} );
while ( %terminating_processes ) {
check_for_processes_to_kill();
sleep(1) if %terminating_processes;
}
if ( 0 ) {
killAll( 5 );
}
dPrint( ZoneMinder::Logger::INFO, "Server shutdown at "
.strftime( '%y/%m/%d %H:%M:%S', localtime() )
dPrint(ZoneMinder::Logger::INFO, "Server shutdown at "
.strftime('%y/%m/%d %H:%M:%S', localtime())
."\n"
);
unlink( main::SOCK_FILE ) or Error( "Unable to unlink " . main::SOCK_FILE .". Error message was: $!" ) if ( -e main::SOCK_FILE );
@ -748,53 +727,54 @@ sub status {
my @args = @_;
if ( defined($daemon) ) {
my $command = join( ' ', $daemon, @args );
my $command = join(' ', $daemon, @args);
my $process = $cmd_hash{$command};
if ( ! $process ) {
dPrint( ZoneMinder::Logger::DEBUG, "'$command' not running\n" );
return();
dPrint(ZoneMinder::Logger::DEBUG, "'$command' not running\n");
return;
}
if ( $process->{pending} ) {
dPrint( ZoneMinder::Logger::DEBUG, "'$process->{command}' pending at "
.strftime( '%y/%m/%d %H:%M:%S', localtime( $process->{pending} ) )
dPrint(ZoneMinder::Logger::DEBUG, "'$command' pending at "
.strftime('%y/%m/%d %H:%M:%S', localtime($process->{pending}))
."\n"
);
} else {
my $cpid = $process->{pid};
if ( ! $pid_hash{$cpid} ) {
dPrint( ZoneMinder::Logger::DEBUG, "'$command' not running\n" );
return();
my $pid = $process->{pid};
if ( ! $pid_hash{$pid} ) {
dPrint(ZoneMinder::Logger::DEBUG, "'$command' not running\n");
return;
}
}
dPrint( ZoneMinder::Logger::DEBUG, "'$process->{command}' running since "
.strftime( '%y/%m/%d %H:%M:%S', localtime( $process->{started} ) )
dPrint(ZoneMinder::Logger::DEBUG, "'$command' running since "
.strftime('%y/%m/%d %H:%M:%S', localtime($process->{started}))
.", pid = $process->{pid}"
);
} else {
foreach my $process ( values(%pid_hash) ) {
foreach my $process ( values %pid_hash ) {
my $out_str = "'$process->{command}' running since "
.strftime( '%y/%m/%d %H:%M:%S', localtime( $process->{started}) )
.strftime('%y/%m/%d %H:%M:%S', localtime($process->{started}))
.", pid = $process->{pid}"
;
$out_str .= ", valid" if ( kill( 0, $process->{pid} ) );
$out_str .= ", valid" if ( kill(0, $process->{pid}) );
$out_str .= "\n";
dPrint( ZoneMinder::Logger::DEBUG, $out_str );
dPrint(ZoneMinder::Logger::DEBUG, $out_str);
}
foreach my $process ( values( %cmd_hash ) ) {
foreach my $process ( values %cmd_hash ) {
if ( $process->{pending} ) {
dPrint( ZoneMinder::Logger::DEBUG, "'$process->{command}' pending at "
.strftime( '%y/%m/%d %H:%M:%S', localtime( $process->{pending} ) )
dPrint(ZoneMinder::Logger::DEBUG, "'$process->{command}' pending at "
.strftime( '%y/%m/%d %H:%M:%S', localtime($process->{pending}))
."\n"
);
}
} # end foreach process
}
}
} # end sub status
sub killAll {
my $delay = shift;
sleep( $delay );
# Why sleep before sending term?
#sleep( $delay );
my $killall;
if ( '@HOST_OS@' eq 'BSD' ) {
$killall = 'killall -q -';
@ -815,6 +795,5 @@ sub killAll {
qx( $cmd );
}
}
1;
__END__

View File

@ -31,8 +31,10 @@ bool zmDbConnected = false;
bool zmDbConnect() {
// For some reason having these lines causes memory corruption and crashing on newer debian/ubuntu
// But they really need to be here in order to prevent a double open of mysql
if ( zmDbConnected )
if ( zmDbConnected ) {
Warning("Calling zmDbConnect when already connected");
return true;
}
if ( !mysql_init(&dbconn) ) {
Error("Can't initialise database connection: %s", mysql_error(&dbconn));

View File

@ -27,9 +27,9 @@ void FFMPEGInit() {
static bool bInit = false;
if ( !bInit ) {
if ( logDebugging() )
av_log_set_level( AV_LOG_DEBUG );
else
//if ( logDebugging() )
//av_log_set_level( AV_LOG_DEBUG );
//else
av_log_set_level( AV_LOG_QUIET );
av_register_all();
avformat_network_init();

View File

@ -146,13 +146,7 @@ FfmpegCamera::~FfmpegCamera() {
}
void FfmpegCamera::Initialise() {
if ( logDebugging() )
av_log_set_level( AV_LOG_DEBUG );
else
av_log_set_level( AV_LOG_QUIET );
av_register_all();
avformat_network_init();
FFMPEGInit();
}
void FfmpegCamera::Terminate() {

View File

@ -410,14 +410,15 @@ Monitor::Monitor(
+ (image_buffer_count*camera->ImageSize())
+ 64; /* Padding used to permit aligning the images buffer to 64 byte boundary */
Debug( 1, "mem.size=%d", mem_size );
Debug(1, "mem.size SharedData=%d TriggerData=%d VideoStoreData=%d total=%d",
sizeof(SharedData), sizeof(TriggerData), sizeof(VideoStoreData), mem_size);
mem_ptr = NULL;
storage = new Storage( storage_id );
Debug(1, "Storage path: %s", storage->Path() );
storage = new Storage(storage_id);
Debug(1, "Storage path: %s", storage->Path());
// Should maybe store this for later use
char monitor_dir[PATH_MAX] = "";
snprintf( monitor_dir, sizeof(monitor_dir), "%s/%d", storage->Path(), id );
snprintf(monitor_dir, sizeof(monitor_dir), "%s/%d", storage->Path(), id);
if ( purpose == CAPTURE ) {
struct stat statbuf;
@ -916,9 +917,9 @@ void Monitor::actionReload() {
void Monitor::actionEnable() {
shared_data->action |= RELOAD;
db_mutex.lock();
static char sql[ZM_SQL_SML_BUFSIZ];
snprintf(sql, sizeof(sql), "UPDATE Monitors SET Enabled = 1 WHERE Id = %d", id);
db_mutex.lock();
if ( mysql_query(&dbconn, sql) ) {
Error("Can't run query: %s", mysql_error(&dbconn));
}

View File

@ -106,44 +106,44 @@ protected:
typedef enum { CLOSE_TIME, CLOSE_IDLE, CLOSE_ALARM } EventCloseMode;
/* sizeof(SharedData) expected to be 336 bytes on 32bit and 64bit */
/* sizeof(SharedData) expected to be 340 bytes on 32bit and 64bit */
typedef struct {
uint32_t size; /* +0 */
uint32_t last_write_index; /* +4 */
uint32_t last_read_index; /* +8 */
uint32_t state; /* +12 */
uint32_t last_event; /* +16 */
uint32_t action; /* +20 */
int32_t brightness; /* +24 */
int32_t hue; /* +28 */
int32_t colour; /* +32 */
int32_t contrast; /* +36 */
int32_t alarm_x; /* +40 */
int32_t alarm_y; /* +44 */
uint8_t valid; /* +48 */
uint8_t active; /* +49 */
uint8_t signal; /* +50 */
uint8_t format; /* +51 */
uint32_t imagesize; /* +52 */
uint32_t epadding1; /* +56 */
uint32_t epadding2; /* +60 */
uint64_t last_event; /* +16 */
uint32_t action; /* +24 */
int32_t brightness; /* +28 */
int32_t hue; /* +32 */
int32_t colour; /* +36 */
int32_t contrast; /* +40 */
int32_t alarm_x; /* +44 */
int32_t alarm_y; /* +48 */
uint8_t valid; /* +52 */
uint8_t active; /* +53 */
uint8_t signal; /* +54 */
uint8_t format; /* +55 */
uint32_t imagesize; /* +56 */
uint32_t epadding1; /* +60 */
uint32_t epadding2; /* +64 */
/*
** This keeps 32bit time_t and 64bit time_t identical and compatible as long as time is before 2038.
** Shared memory layout should be identical for both 32bit and 64bit and is multiples of 16.
*/
union { /* +64 */
union { /* +68 */
time_t startup_time; /* When the zmc process started. zmwatch uses this to see how long the process has been running without getting any images */
uint64_t extrapad1;
};
union { /* +72 */
union { /* +76 */
time_t last_write_time;
uint64_t extrapad2;
};
union { /* +80 */
union { /* +84 */
time_t last_read_time;
uint64_t extrapad3;
};
uint8_t control_state[256]; /* +88 */
uint8_t control_state[256]; /* +92 */
char alarm_cause[256];
@ -174,7 +174,7 @@ protected:
//sizeOf(VideoStoreData) expected to be 4104 bytes on 32bit and 64bit
typedef struct {
uint32_t size;
unsigned long long current_event;
uint64_t current_event;
char event_file[4096];
timeval recording; // used as both bool and a pointer to the timestamp when recording should begin
//uint32_t frameNumber;
@ -206,7 +206,6 @@ protected:
int last_state;
uint64_t last_event;
public:
MonitorLink( int p_id, const char *p_name );
~MonitorLink();
@ -318,8 +317,6 @@ protected:
#endif // ZM_MEM_MAPPED
off_t mem_size;
unsigned char *mem_ptr;
Storage *storage;
SharedData *shared_data;
TriggerData *trigger_data;
VideoStoreData *video_store_data;
@ -329,8 +326,8 @@ protected:
Snapshot *pre_event_buffer;
Camera *camera;
Event *event;
Event *event;
Storage *storage;
int n_zones;
Zone **zones;

@ -1 +1 @@
Subproject commit ea90c0cd7f6e24333a90885e563b5d30b793db29
Subproject commit ca91b87fda8e006e4fca2ed870f24f9a29c2905d

@ -1 +1 @@
Subproject commit 0bd63fb464957080ead342db58ca9e01532cf1ef
Subproject commit 1351dde6b4c75b215099ae8bcf5a21d6c6e10298