mutualExclusion.php
3.47 KB
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
<?php
/***************************************************************************
* This gives a method of mutual exclusion for critical Sections within
* your script. A lock-file will be created for every critical section that
* must be secured. The file hold information about the lock and is a
* handle (name) for the lock, so that every script uses the same lock.
* The lock will be achieved by one of two ways.
*
* 1. by using semaphores if they are available within the current php
* installation.
* 2. else by using flock, which exists within every php installation.
*
* Semaphores are used in favour because flock did not work reliably in
* threaded environments. That means, if we have no semaphores and are
* in a threaded environment these functions are also not reliable.
* In doubt ask your administrator or provider.
*
* Author: Georg Steffers <georg@steffers.org
* Date: 14th Oct. 2007
***************************************************************************/
require_once dirname(__FILE__) . '/../config.php';
require_once LIBDIR . 'errException.php';
/**
* Try to acquire a lock to enter a critical section. If the lock is already
* acquired the function blocks until the lock id freed again. If more than
* one process waits for the lock, than it is undefined which process get
* the lock next. This depends on which process gets CPU time first. All other
* processes continue waiting.
*
* Sideeffects:
* If this function succeeds ignore_user_abort is set to TRUE so that the
* critical section might not be interruped by a user abort. This can
* but shouldn't be changed within the critical section and will be reset
* in releaseLock.
*
* Arguments:
* $lockFile <string>: Path and basename to the lockfile to use.
* $csId <string[1]>: Id of the critical section, will be part of filename.
* $msg <string>: The message to be written to the lockfile.
*
* If $msg is NULL, a default message is created from session_id and time
*
* Returns:
* Array of lock information.
* [0] Filehandle to opened lockfile.
* [1] Resource id for semaphor
* [2] the old setting of ignore_user_abort.
*/
function acquireLock ($lockFile, $csId, $msg = NULL)
{
$fName = $lockFile . $csId . '.lck';
$lock = NULL;
setErrExceptionMapping ();
$lockHandle = fopen ($fName, 'w');
// if available use semaphores for mutual exclusion because flock
// doesn't work reliably in threaded environments.
if (function_exists ('sem_get'))
{
$lock = sem_get (ftok ($fName, $csId), 1, 0644, TRUE);
$state = sem_acquire ($lock);
while ($state === FALSE)
$state = sem_acquire ($lock);
}
else
{
$state = flock ($lock, LOCK_EX);
while ($state === FALSE)
$state = flock ($lock, LOCK_EX);
}
// Here one could write informations in the lockfile...time, pid, etc.
if ($msg === NULL)
$msg = session_id () . '::' . time ();
fwrite ($lockHandle, $msg . "\n");
fflush ($lockHandle);
resetErrExceptionMapping ();
$userAbort = ignore_user_abort(TRUE);
return array ($lockHandle, $lock, $userAbort);
}
/**
* Release a lock previously acquired by acquireLock.
*
* Sideeffects:
* Sets ignore_user_abort to the value before acquireLock succeds.
*
* Arguments:
* $lock <array[3]>: The array returned by a successfull acquireLock call.
*/
function releaseLock ($lock)
{
setErrExceptionMapping ();
if ($lock[1] !== NULL)
sem_release ($lock[1]);
ftruncate ($lock[0], 0);
fclose ($lock[0]);
resetErrExceptionMapping ();
ignore_user_abort($lock[2]);
}
?>