::itcl::class ::qw::mutex_manager_class { /* { 2.38.5 - switched windows back to real interprocess named mutexes. We are using a server socket port number as a mutex. We have the mutex open iff we have the socket open. We can't open the socket if any other process has it open. Hence we have a mutex. Also, the socket is definitely closed if the process is unexpectedly terminated for any reason. The nv2_process.txt file is protected by the mutex. We can only access the file when we have the server open on the specified port. Problem scenario: Process A asks if mutex is locked. The server port is not open so we presume it is not locaked. But suppose we then lock it by opening the server port, but this fails because another process grabbed the server port in the the time between the is_loacked call and the lock call. Motes on named semaphore posix sem_init sem_open sem_wait sem_post sem_close name does not have to map to file system V semget semop semctl */ } protected variable _mutex_array; # each mutex has an entry in this array protected variable _port_number 10000; protected variable _mutex_type ""; /* { Ports 49152-65535 are supposedly free to be used by clients. */ } method constructor {} { ::array set _mutex_array {}; ::switch -- $::tcl_platform(platform) { "windows" { ::set _mutex_type "mutex_type_socket"; ::set _mutex_type "mutex_type_windows_mutex"; } "unix" { ::set _mutex_type "mutex_type_flock"; ::set _mutex_type "mutex_type_socket"; } } } method dummy_callback {args} { } method mutex_is_locked {sargs} { ::set rwb1_debug 0; ::set MutexName [::sargs::get $sargs .mutex_name]; ::if {$rwb1_debug} {::puts "rwb1_debug,mutex_is_locked,1000.0,MutexName==$MutexName";} ::if {$MutexName eq ""} { ::qw::bug 314120230824175333 "[::qw::methodname] - empty mutex name."; } ::switch -- $_mutex_type { "mutex_type_windows_mutex" { ::if {$rwb1_debug} {::puts "rwb1_debug,mutex_is_locked,1000.1";} ::if {![::info exists _mutex_array($MutexName)]} { ::if {$rwb1_debug} {::puts "rwb1_debug,mutex_is_locked,1000.2";} ::return 0; } ::if {[::sargs::get $_mutex_array($MutexName) .mutex_handle] eq ""} { ::if {$rwb1_debug} {::puts "rwb1_debug,mutex_is_locked,1000.3";} ::return 0; } ::if {$rwb1_debug} {::puts "rwb1_debug,mutex_is_locked,1000.4";} } "mutex_type_socket" { ::if {![::info exists _mutex_array($MutexName)]} { ::if {$rwb1_debug} {::puts "rwb1_debug,mutex_is_locked,1000.5";} ::return 0; } ::if {[::sargs::get $_mutex_array($MutexName) .socket] eq ""} { ::if {$rwb1_debug} {::puts "rwb1_debug,mutex_is_locked,1000.6";} ::return 0; } ::if {$rwb1_debug} {::puts "rwb1_debug,mutex_is_locked,1000.7";} } "mutex_type_flock" { ::if {![::info exists _mutex_array($MutexName)]} { ::if {$rwb1_debug} {::puts "rwb1_debug,mutex_is_locked,1000.8";} ::return 0; } ::set Mutex [::sargs::get $_mutex_array($MutexName) .mutex]; ::if {$Mutex eq ""} { ::if {$rwb1_debug} {::puts "rwb1_debug,mutex_is_locked,1000.9";} ::return 0; } ::set Result [$Mutex cpp_mutex_is_locked]; ::if {$rwb1_debug} {::puts "rwb1_debug,mutex_is_locked,1000.10";} ::return $Result; } } ::if {$rwb1_debug} {::puts "rwb1_debug,mutex_is_locked,1000.11";} ::return 1; } method mutex_lock {sargs} { ::set rwb1_debug 0; ::if {$::qw::verbose(mutex)} { ::set rwb1_debug 2; } ::set MutexName [::sargs::get $sargs .mutex_name]; ::qw::profile::finally "mutex_lock-$MutexName"; ::set LockCaller [::sargs::get $sargs .lock_caller]; ::if {$rwb1_debug} {::puts "rwb1_debug,mutex_lock,1000.0,MutexName==$MutexName,LockCaller==$LockCaller";} ::if {$MutexName eq ""} { ::qw::bug 314120230824175331 "[::qw::methodname] - empty mutex name."; } ::if {[mutex_is_locked $sargs]} { ::qw::bug 314120230828081604 "[::qw::methodname] - mutex already locked - LockCaller==$LockCaller."; } ::switch -- $_mutex_type { "mutex_type_windows_mutex" { ::if {$rwb1_debug} {::puts "rwb1_debug,mutex_lock,1000.1";} ::set Handle [::qw::mutex_lock .mutex_name $MutexName]; ::sargs::var::set _mutex_array($MutexName) .mutex_handle $Handle; ::sargs::var::set _mutex_array($MutexName) .milliseconds [::clock clicks -milliseconds]; ::sargs::var::set _mutex_array($MutexName) .lock_caller $LockCaller; ::if {$rwb1_debug} {::puts "rwb1_debug,mutex_lock,1000.1";} } "mutex_type_socket" { ::set Socket ""; ::while {$Socket eq ""} { ::qw::try { ::set Socket [::socket -server [::list $this dummy_callback] $_port_number]; } catch Exception { /* { We could just go as fast as possible, resembling an infinite loop, but let's back off a bit by sleeping a little. */ } ::qw::sleep 100; } } ::sargs::var::set _mutex_array($MutexName) .socket $Socket; ::sargs::var::set _mutex_array($MutexName) .milliseconds [::clock clicks -milliseconds]; ::sargs::var::set _mutex_array($MutexName) .lock_caller $LockCaller; } "mutex_type_flock" { ::set Handle [::qw::mutex_lock .mutex_name $MutexName]; ::sargs::var::set _mutex_array($MutexName) .mutex_handle $Handle; ::sargs::var::set _mutex_array($MutexName) .milliseconds [::clock clicks -milliseconds]; ::sargs::var::set _mutex_array($MutexName) .lock_caller $LockCaller; } } } method mutex_unlock {sargs} { ::set rwb1_debug 0; ::if {$::qw::verbose(mutex)} { ::set rwb1_debug 2; } ::set MutexName [::sargs::get $sargs .mutex_name]; ::if {$MutexName eq ""} { ::qw::bug 314120230824175332 "[::qw::methodname] - empty mutex name."; } ::set UnlockCaller [::sargs::get $sargs .unlock_caller]; ::if {$rwb1_debug} {::puts "rwb1_debug,mutex_unlock,1000.0,MutexName==$MutexName,UnlockCaller==$UnlockCaller";} ::if {![::info exists _mutex_array($MutexName)]} { ::if {$rwb1_debug} {::puts "rwb1_debug,mutex_unlock,1000.1";} ::return; } ::switch -- $_mutex_type { "mutex_type_windows_mutex" { ::if {$rwb1_debug} {::puts "rwb1_debug,mutex_unlock,1000.2";} ::set MutexHandle [::sargs::get $_mutex_array($MutexName) .mutex_handle]; ::if {$MutexHandle eq ""} { /* { The mutex was not locked so nothing to do. */ } ::if {$rwb1_debug} {::puts "rwb1_debug,mutex_unlock,1000.3";} ::return; } ::if {$rwb1_debug} { ::set LockCaller [::sargs::get $_mutex_array($MutexName) .lock_caller]; ::puts "rwb1_debug,mutex_unlock,1000.00,LockCaller==\"$LockCaller\""; } ::qw::mutex_unlock .mutex_handle $MutexHandle; ::sargs::var::set _mutex_array($MutexName) .mutex_handle ""; ::sargs::var::set _mutex_array($MutexName) .lock_caller ""; ::sargs::var::set _mutex_array($MutexName) .milliseconds ""; ::if {$rwb1_debug} {::puts "rwb1_debug,mutex_unlock,1000.5";} } "mutex_type_socket" { ::set Socket [::sargs::get $_mutex_array($MutexName) .socket]; ::if {$Socket eq ""} { /* { The mutex was not locked so nothing to do. */ } ::return; } ::if {$rwb1_debug} { ::set LockCaller [::sargs::get $_mutex_array($MutexName) .lock_caller]; ::puts "rwb1_debug,mutex_unlock,1000.00,LockCaller==\"$LockCaller\""; } ::close $Socket; ::sargs::var::set _mutex_array($MutexName) .socket ""; ::sargs::var::set _mutex_array($MutexName) .lock_caller ""; ::sargs::var::set _mutex_array($MutexName) .milliseconds ""; } "mutex_type_flock" { ::set MutexHandle [::sargs::get $_mutex_array($MutexName) .mutex_handle]; ::if {$MutexHandle eq ""} { /* { The mutex was not locked so nothing to do. */ } ::if {$rwb1_debug} {::puts "rwb1_debug,mutex_unlock,1000.3";} ::return; } ::if {$rwb1_debug} { ::set LockCaller [::sargs::get $_mutex_array($MutexName) .lock_caller]; ::puts "rwb1_debug,mutex_unlock,1000.00,LockCaller==\"$LockCaller\""; } ::qw::mutex_unlock .mutex_handle $MutexHandle; ::sargs::var::set _mutex_array($MutexName) .mutex_handle ""; ::sargs::var::set _mutex_array($MutexName) .lock_caller ""; ::sargs::var::set _mutex_array($MutexName) .milliseconds ""; } } } } ::qw::mutex_manager_class ::qw::mutex_manager;