Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

280 lines
7.9 KiB

  1. #---------------------------------------------------------------------
  2. package LockProc;
  3. #
  4. # Copyright (c) Microsoft Corporation. All rights reserved.
  5. #
  6. # Version: 1.00 (01/01/2001) : BPerkins
  7. # 2.00 (10/16/2001) : SuemiaoR
  8. # Purpose: Create locking to prevent multiple processes at the same time.
  9. #---------------------------------------------------------------------
  10. use strict;
  11. use vars qw($VERSION);
  12. $VERSION = '1.00';
  13. use Win32::ChangeNotify;
  14. use Win32::Event;
  15. use Logmsg;
  16. use comlib;
  17. #---------------------------------------------------------------------
  18. sub new
  19. {
  20. my $class = shift;
  21. my $spool_path = shift;
  22. my $timeout = shift;
  23. return 0 if not defined $spool_path;
  24. my $instance =
  25. {
  26. Path => $spool_path,
  27. Timeout => $timeout || INFINITE, # default timeout is INFINITE
  28. File => "$ENV{COMPUTERNAME}.txt",
  29. NotificationObj => undef,
  30. LocalSyncObj => undef,
  31. fHaveLocalSync => 0,
  32. Count => 0
  33. };
  34. return bless $instance;
  35. }
  36. #---------------------------------------------------------------------
  37. sub Lock
  38. {
  39. my $self = shift;
  40. my $wait_return;
  41. return 0 unless ref $self;
  42. # If we already hold the lock just bump up the ref-count
  43. if ( $self->{Count} )
  44. {
  45. $self->{Count}++;
  46. return 1;
  47. }
  48. # Need to synchronize local access (only one program
  49. # at a time from the same machine can hold the lock)
  50. dbgmsg( "Creating a local request event..." );
  51. if ( !defined $self->{LocalSyncObj} )
  52. {
  53. my $lock_path = $self->{Path};
  54. $lock_path =~ s/\\\\/remote\\/;
  55. $lock_path =~ s/\\/\//g;
  56. if( !($self->{LocalSyncObj} = new Win32::Event ( 0, 1, "Global\\$lock_path" ) ))
  57. {
  58. errmsg( "Unable to create a local event ($^E)." );
  59. errmsg( "Check if the same process is running in this machine." );
  60. return 0;
  61. }
  62. }
  63. dbgmsg( "Checking global lock status ..." );
  64. if ( !$self->{fHaveLocalSync} )
  65. {
  66. # Handle timeout
  67. if( !($wait_return = $self->{LocalSyncObj}->wait( $self->{Timeout} ) ) )
  68. {
  69. dbgmsg( "Waiting on another process on machine." );
  70. return 2;
  71. }
  72. # Handle error condition
  73. elsif ( $wait_return != 1 )
  74. {
  75. errmsg( "Unexpected error waiting for local synchronization (wait returned ". $wait_return. ")" );
  76. return 0;
  77. }
  78. $self->{fHaveLocalSync} = 1;
  79. }
  80. # Check for our existence before we create a file in the queue
  81. # (this will be the case if something bad happened on the last run and we are
  82. # rerunning the command to recover)
  83. if ( ! -e "$self->{Path}\\$self->{File}" )
  84. {
  85. if( !open SPOOLFILE, "> $self->{Path}\\$self->{File}" )
  86. {
  87. errmsg( "Failed to create synchronization file '$self->{Path}\\$self->{File}' ($!)." );
  88. return 0;
  89. }
  90. print SPOOLFILE "This file is used to synchronize access among machines.";
  91. close SPOOLFILE;
  92. }
  93. # Create the notification object if this is the first time we were called
  94. dbgmsg( "Creating the notification object..." );
  95. if( !$self->{NotificationObj} )
  96. {
  97. if( !($self->{NotificationObj} = new Win32::ChangeNotify( $self->{Path}, 0, FILE_NOTIFY_CHANGE_FILE_NAME ) ))
  98. {
  99. errmsg( "Failed creating monitor object ($^E)." );
  100. return 0;
  101. }
  102. }
  103. # Check our position in the 'queue' at the beginning
  104. dbgmsg( "Looking up the waiting queue..." );
  105. my $tmpfile = "$ENV{TEMP}\\tmpfile";
  106. if ( system("dir /b /od $self->{Path} > $tmpfile") )
  107. {
  108. errmsg( "Unable to view directory $self->{Path}." );
  109. return 0;
  110. }
  111. my @ordered_spool_directory = &comlib::ReadFile($tmpfile);
  112. dbgmsg( "The Waiting queue [@ordered_spool_directory]" ) if( @ordered_spool_directory > 1 );
  113. # We are at the top
  114. if ( $ordered_spool_directory[0] eq $self->{File} )
  115. {
  116. $self->{Count}++;
  117. dbgmsg( "Pass semaphore verification.");
  118. return 1;
  119. }
  120. # Recheck our position in the 'queue' everytime the state of the directory changes
  121. # until we are in the top position
  122. # or we hit the timeout value with no activity
  123. while ( 1 )
  124. {
  125. $self->{NotificationObj}->reset();
  126. $wait_return = $self->{NotificationObj}->wait( $self->{Timeout} );
  127. if ( system("dir /b /od $self->{Path} > $tmpfile") )
  128. {
  129. errmsg( "Unable to view directory $self->{Path}." );
  130. return 0;
  131. }
  132. @ordered_spool_directory = &comlib::ReadFile($tmpfile);
  133. # We are at the top
  134. if ( $ordered_spool_directory[0] eq $self->{File} )
  135. {
  136. $self->{Count}++;
  137. return 1;
  138. }
  139. # Still waiting for others
  140. # But need to Make sure we are still in the queue
  141. my $found_self = 0;
  142. for ( @ordered_spool_directory )
  143. {
  144. if ( $_ eq "$self->{File}" ){ $found_self = 1; last;}
  145. }
  146. if ( !$found_self )
  147. {
  148. # Lost our synchronization file -- recreating...
  149. if ( !(open SPOOLFILE, "> $self->{Path}\\$self->{File}" ) )
  150. {
  151. errmsg( "Lost our synchronization file '$self->{Path}\\$self->{File}' -- failed to recreate. ($!)." );
  152. return 0;
  153. }
  154. print SPOOLFILE "This file is used to synchronize access among machines.";
  155. close SPOOLFILE;
  156. }
  157. # Handle timeout
  158. if ( !$wait_return )
  159. {
  160. my $machine_name = $ordered_spool_directory[0];
  161. $machine_name =~ s/\.txt$//;
  162. wrnmsg ( "Waiting on $machine_name ($self->{Path}\\$ordered_spool_directory[0])." );
  163. return 2;
  164. }
  165. # Handle error condition
  166. elsif ( $wait_return != 1 )
  167. {
  168. errmsg( "Unexpected error waiting on directory to change (wait returned ". $wait_return. ")" );
  169. return 0;
  170. }
  171. }
  172. errmsg( "Jumped out of an infinte loop -- no idea how we got here" );
  173. return 1;
  174. }
  175. #---------------------------------------------------------------------
  176. sub Unlock
  177. {
  178. my $self = shift;
  179. return unless ref $self;
  180. # Can't release a lock we don't hold
  181. return 0 if ( !$self->{Count} );
  182. # Decrement lock count
  183. if ( !( --$self->{Count} ) )
  184. {
  185. if ( ! unlink "$self->{Path}\\$self->{File}" )
  186. {
  187. errmsg("Failed to delete synchronization file ($self->{Path}\\$self->{File}).");
  188. errmsg("May need to delete by hand." );
  189. return 0;
  190. }
  191. $self->{LocalSyncObj}->set();
  192. }
  193. return 1;
  194. }
  195. #---------------------------------------------------------------------
  196. sub GetLastError
  197. {
  198. my $self = shift;
  199. return unless ref $self;
  200. #return $self->{LastErrorValue};
  201. }
  202. #---------------------------------------------------------------------
  203. sub GetLastErrorMessage
  204. {
  205. my $self = shift;
  206. return unless ref $self;
  207. #return $self->{LastErrorMsg};
  208. }
  209. #---------------------------------------------------------------------
  210. sub DESTROY
  211. {
  212. my $self = shift;
  213. return unless ref $self;
  214. if ( $self->{Count} > 0 )
  215. {
  216. #print "Abandoning lock file -- attempting to delete.";
  217. $self->{Count} = 1;
  218. return $self->Unlock();
  219. }
  220. else
  221. {
  222. $self->{LocalSyncObj}->set() if ( $self->{fHaveLocalSync} ) ;
  223. return 1;
  224. }
  225. }
  226. #---------------------------------------------------------------------
  227. 1;
  228. __END__
  229. =head1 NAME
  230. <<mypackage>> - <<short description>>
  231. =head1 SYNOPSIS
  232. <<A short code example>>
  233. =head1 DESCRIPTION
  234. <<The purpose and functionality of this module>>
  235. =head1 AUTHOR
  236. <<your alias>>
  237. =head1 COPYRIGHT
  238. Copyright (c) Microsoft Corporation. All rights reserved.
  239. =cut