source: src/mlx/singleton.py@ 265:441bc4537a91

Last change on this file since 265:441bc4537a91 was 247:12a62baf908f, checked in by István Váradi <ivaradi@…>, 12 years ago

Hopefully fixed the problem of not restarting properly

File size: 10.2 KB
Line 
1# Module to allow for a single instance of an application to run
2
3import os
4import time
5
6#----------------------------------------------------------------------------
7
8if os.name=="nt":
9 import win32event
10 import win32file
11 import win32pipe
12 import win32api
13 import winerror
14
15 import threading
16
17 class _PipeServer(threading.Thread):
18 """A server that creates a named pipe, and waits for messages on
19 that."""
20
21 BUFFER_SIZE = 4096
22
23 def __init__(self, pipeName, raiseCallback):
24 """Construct the server thread."""
25 super(_PipeServer, self).__init__()
26
27 self._pipeName = pipeName
28 self._raiseCallback = raiseCallback
29 self.daemon = True
30
31 def run(self):
32 """Perform the operation of the thread."""
33 try:
34 while True:
35 handle = self._createPipe()
36
37 if handle is None:
38 break
39
40 print "singleton._PipeServer.run: created the pipe"
41 try:
42 if win32pipe.ConnectNamedPipe(handle)==0:
43 print "singleton._PipeServer.run: client connection received"
44 (code, message) = \
45 win32file.ReadFile(handle,
46 _PipeServer.BUFFER_SIZE,
47 None)
48
49 if code==0:
50 print "singleton._PipeServer.run: message received from client"
51 self._raiseCallback()
52 else:
53 print "singleton._PipeServer.run: failed to read from the pipe"
54 except Exception, e:
55 print "singleton._PipeServer.run: exception:", str(e)
56 finally:
57 win32pipe.DisconnectNamedPipe(handle)
58 win32file.CloseHandle(handle)
59 except Exception, e:
60 print "singleton._PipeServer.run: fatal exception:", str(e)
61
62 def _createPipe(self):
63 """Create the pipe."""
64 handle = win32pipe.CreateNamedPipe(self._pipeName,
65 win32pipe.PIPE_ACCESS_INBOUND,
66 win32pipe.PIPE_TYPE_BYTE |
67 win32pipe.PIPE_READMODE_BYTE |
68 win32pipe.PIPE_WAIT,
69 win32pipe.PIPE_UNLIMITED_INSTANCES,
70 _PipeServer.BUFFER_SIZE,
71 _PipeServer.BUFFER_SIZE,
72 1000,
73 None)
74 if handle==win32file.INVALID_HANDLE_VALUE:
75 print "singleton._PipeServer.run: could not create the handle"
76 return None
77 else:
78 return handle
79
80 class SingleInstance(object):
81 """Creating an instance of this object checks if only one instance of
82 the process runs."""
83 def __init__(self, baseName, raiseCallback):
84 """Construct the single instance object.
85
86 raiseCallback is a function that will be called, if another
87 instance of the program is started."""
88 self._name = baseName + "_" + win32api.GetUserName()
89 self._mutex = win32event.CreateMutex(None, False, self._name)
90 self._isSingle = win32api.GetLastError() != \
91 winerror.ERROR_ALREADY_EXISTS
92 if self._isSingle:
93 self._startPipeServer(raiseCallback)
94 else:
95 self._notifySingleton()
96
97 def close(self):
98 """Close the instance by closing the mutex."""
99 if self._mutex:
100 win32api.CloseHandle(self._mutex)
101 self._mutex = None
102
103 def _getPipeName(self):
104 """Get the name of the pipe to be used for communication."""
105 return r'\\.\pipe\\' + self._name
106
107 def _startPipeServer(self, raiseCallback):
108 """Start the pipe server"""
109 pipeServer = _PipeServer(self._getPipeName(),
110 raiseCallback)
111 pipeServer.start()
112
113 def _notifySingleton(self):
114 """Notify the already running instance of the program of our
115 presence."""
116 pipeName = self._getPipeName()
117 for i in range(0, 3):
118 try:
119 f = open(pipeName, "wb")
120 f.write("hello")
121 f.close()
122 return
123 except Exception, e:
124 print "SingleInstance._notifySingleton: failed:", str(e)
125 time.sleep(0.5)
126
127 def __nonzero__(self):
128 """Return a boolean representation of the object.
129
130 It is True, if this is the single instance of the program."""
131 return self._isSingle
132
133 def __del__(self):
134 """Destroy the object."""
135 self.close()
136
137#----------------------------------------------------------------------------
138
139else: # os.name=="nt"
140 import fcntl
141 import socket
142 import tempfile
143 import threading
144
145 class _SocketServer(threading.Thread):
146 """Server thread to handle the Unix socket through which we are
147 notified of other instances starting."""
148 def __init__(self, socketName, raiseCallback):
149 """Construct the server."""
150 super(_SocketServer, self).__init__()
151
152 self._socketName = socketName
153 self._raiseCallback = raiseCallback
154
155 self.daemon = True
156
157
158 def run(self):
159 """Perform the thread's operation."""
160 try:
161 try:
162 os.remove(self._socketName)
163 except:
164 pass
165
166 s = socket.socket(socket.AF_UNIX, socket.SOCK_DGRAM)
167 s.bind(self._socketName)
168
169 while True:
170 s.recv(64)
171 self._raiseCallback()
172 except Exception, e:
173 print "singleton._SocketServer.run: fatal exception:", str(e)
174
175 class SingleInstance(object):
176 """Creating an instance of this object checks if only one instance of
177 the process runs."""
178 def __init__(self, baseName, raiseCallback):
179 """Construct the single instance object.
180
181 raiseCallback is a function that will be called, if another
182 instance of the program is started."""
183 baseName = baseName + "_" + os.environ["LOGNAME"]
184
185 tempDir = tempfile.gettempdir()
186 self._lockName = os.path.join(tempDir, baseName + ".lock")
187 self._socketName = os.path.join(tempDir, baseName + ".sock")
188
189 self._lockFile = open(self._lockName, "w")
190
191 self._isSingle = False
192 try:
193 fcntl.lockf(self._lockFile, fcntl.LOCK_EX | fcntl.LOCK_NB)
194 self._isSingle = True
195 except Exception, e:
196 self._lockFile.close()
197 self._lockFile = None
198 pass
199
200 if self._isSingle:
201 self._startSocketServer(raiseCallback)
202 else:
203 self._notifySingleton()
204
205 def close(self):
206 """Close the instance by closing the mutex."""
207 if self._isSingle:
208 if self._lockFile:
209 self._lockFile.close()
210 self._lockFile = None
211 try:
212 os.remove(self._lockName)
213 except:
214 pass
215 try:
216 os.remove(self._socketName)
217 except:
218 pass
219
220
221 def _startSocketServer(self, raiseCallback):
222 """Start the pipe server"""
223 pipeServer = _SocketServer(self._socketName, raiseCallback)
224 pipeServer.start()
225
226 def _notifySingleton(self):
227 """Notify the already running instance of the program of our
228 presence."""
229 s = socket.socket(socket.AF_UNIX, socket.SOCK_DGRAM)
230 for i in range(0, 3):
231 try:
232 s.connect(self._socketName)
233 s.send("hello")
234 s.close()
235 return
236 except Exception, e:
237 print "singleton.SingleInstance._notifySingleton: failed:", str(e)
238 time.sleep(0.5)
239
240 def __nonzero__(self):
241 """Return a boolean representation of the object.
242
243 It is True, if this is the single instance of the program."""
244 return self._isSingle
245
246 def __del__(self):
247 """Destroy the object."""
248 self.close()
249
250#----------------------------------------------------------------------------
251#----------------------------------------------------------------------------
252
253# MAVA Logger X-specific stuff
254
255#----------------------------------------------------------------------------
256
257# The callback to use
258raiseCallback = None
259
260#----------------------------------------------------------------------------
261
262def raiseCallbackWrapper():
263 """The actual function to be used as the callback.
264
265 It checks if raiseCallback is None, and if not, it calls that."""
266 callback = raiseCallback
267 if callback is not None:
268 callback()
269
270#----------------------------------------------------------------------------
271#----------------------------------------------------------------------------
272
273if __name__=="__main__":
274 def raiseCallback():
275 print "Raise the window!"
276
277 instance = SingleInstance("mlx", raiseCallback)
278 if instance:
279 print "The first instance"
280 time.sleep(10)
281 else:
282 print "The program is already running."
283
Note: See TracBrowser for help on using the repository browser.