This repository has been archived by the owner on Dec 14, 2020. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 20
/
Lock.cs
executable file
·114 lines (105 loc) · 3.13 KB
/
Lock.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
using System;
using System.Diagnostics;
using System.IO;
using System.Threading;
using log4net;
namespace MonkeyWrench
{
public class Lock
{
static readonly ILog log = LogManager.GetLogger (typeof (Lock));
Mutex mutex;
Semaphore semaphore;
FileStream file;
string file_existence;
private Lock ()
{
}
/// <summary>
/// Try to aquire a machine-wide lock named 'name'. Returns null in case of failure (it doesn't wait at all).
/// </summary>
/// <param name="name"></param>
/// <returns></returns>
public static Lock Create (string name)
{
Lock result = new Lock ();
Mutex mutex;
Semaphore semaphore;
switch (Configuration.LockingAlgorithm.ToLowerInvariant ()) {
case "mutex":
mutex = new Mutex (true, name);
if (mutex.WaitOne (1 /* ms */)) {
result.mutex = mutex;
return result;
}
return null;
case "file":
try {
result.file = File.Open (Path.Combine (Path.GetTempPath (), name + ".lock"), FileMode.Create, FileAccess.ReadWrite, FileShare.Read);
return result;
} catch (IOException ex) {
log.WarnFormat ("Could not aquire builder lock: {0}", ex);
return null;
}
case "fileexistence":
case "fileexistance":
string tmp = Path.Combine (Path.GetTempPath (), name + ".fileexistence-lock--delete-to-unlock");
log.DebugFormat ("Checking file existence for {0}", tmp);
if (File.Exists (tmp)) {
try {
var contents = File.ReadAllText (tmp);
int pid;
if (!int.TryParse (contents, out pid)) {
log.DebugFormat ("File lock contains invalid data ('{0}' size: {1}), lock acquired", contents, contents.Length);
} else if (ProcessHelper.Exists (pid)) {
log.Debug ("File lock corresponds to an existing process. Lock NOT acquired.");
return null;
} else {
log.Debug ("File lock corresponds to a dead process, lock acquired");
}
} catch (Exception ex) {
log.ErrorFormat ("Could not confirm that file lock corresponds to a non-existing process: {0}", ex);
return null;
}
}
// there is a race condition here.
// given that the default setup is to execute a program at most once per minute,
// the race condition is harmless.
File.WriteAllText (tmp, Process.GetCurrentProcess ().Id.ToString ());
result.file_existence = tmp;
return result;
case "semaphore":
semaphore = new Semaphore (1, 1, name);
if (semaphore.WaitOne (1 /* ms */)) {
result.semaphore = semaphore;
return result;
}
return null;
default:
log.ErrorFormat ("Unknown locking algorithm: {0} (using default 'semaphore')", Configuration.LockingAlgorithm);
goto case "semaphore";
}
}
public void Unlock ()
{
try {
if (mutex != null) {
mutex.ReleaseMutex ();
} else if (semaphore != null) {
semaphore.Release ();
} else if (file != null) {
file.Close ();
} else if (file_existence != null) {
File.Delete (file_existence);
}
} catch (Exception ex) {
log.ErrorFormat ("Exception while unlocking process lock (file existence): {0}", ex);
}
GC.SuppressFinalize (this);
}
~Lock ()
{
Unlock ();
}
}
}