~ubuntu-branches/ubuntu/karmic/gnustep-base/karmic

« back to all changes in this revision

Viewing changes to Source/NSDistributedLock.m

  • Committer: Bazaar Package Importer
  • Author(s): Eric Heintzmann
  • Date: 2005-04-17 00:14:38 UTC
  • mfrom: (1.2.1 upstream) (2.1.2 hoary)
  • Revision ID: james.westby@ubuntu.com-20050417001438-enf0y07c9tku85z1
Tags: 1.10.3-1
New upstream release.

Show diffs side-by-side

added added

removed removed

Lines of Context:
21
21
   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA.
22
22
 
23
23
   <title>NSDistributedLock class reference</title>
24
 
   $Date: 2001/12/18 16:54:14 $ $Revision: 1.12 $
 
24
   $Date: 2005/02/22 11:22:44 $ $Revision: 1.20 $
25
25
   */
26
26
 
27
 
#include <config.h>
 
27
#include "config.h"
28
28
#include <string.h>
29
 
#include <Foundation/NSDistributedLock.h>
30
 
#include <Foundation/NSFileManager.h>
31
 
#include <Foundation/NSException.h>
32
 
#include <Foundation/NSValue.h>
33
 
#include <Foundation/NSDebug.h>
 
29
#include "Foundation/NSDistributedLock.h"
 
30
#include "Foundation/NSFileManager.h"
 
31
#include "Foundation/NSException.h"
 
32
#include "Foundation/NSValue.h"
 
33
#include "Foundation/NSDebug.h"
34
34
 
35
35
#include <fcntl.h>
36
36
 
 
37
static NSFileManager    *mgr = nil;
 
38
 
 
39
/**
 
40
 *  This class does not adopt the [(NSLocking)] protocol but supports locking
 
41
 *  across processes, including processes on different machines, as long as
 
42
 *  they can access a common filesystem.
 
43
 */
37
44
@implementation NSDistributedLock
38
45
 
 
46
+ (void) initialize
 
47
{
 
48
  if (mgr == nil)
 
49
    {
 
50
      mgr = RETAIN([NSFileManager defaultManager]);
 
51
    }
 
52
}
 
53
 
 
54
/**
 
55
 * Return a distributed lock for aPath.
 
56
 * See -initWithPath: for details.
 
57
 */
39
58
+ (NSDistributedLock*) lockWithPath: (NSString*)aPath
40
59
{
41
60
  return AUTORELEASE([[self alloc] initWithPath: aPath]);
42
61
}
43
62
 
 
63
/**
 
64
 * Forces release of the lock whether the receiver owns it or not.<br />
 
65
 * Raises an NSGenericException if unable to remove the lock.
 
66
 */
44
67
- (void) breakLock
45
68
{
46
 
  NSFileManager *fileManager;
47
 
 
48
 
  fileManager = [NSFileManager defaultManager];
49
 
  if ([fileManager removeFileAtPath: _lockPath handler: nil] == NO)
50
 
    [NSException raise: NSGenericException 
51
 
                format: @"Failed to remove lock directory '%@' - %s",
52
 
                _lockPath, GSLastErrorStr(errno)];
53
 
  RELEASE(_lockTime);
54
 
  _lockTime = nil;
 
69
  NSDictionary  *attributes;
 
70
 
 
71
  DESTROY(_lockTime);
 
72
  attributes = [mgr fileAttributesAtPath: _lockPath traverseLink: YES];
 
73
  if (attributes != nil)
 
74
    {
 
75
      NSDate    *modDate = [attributes fileModificationDate];
 
76
 
 
77
      if ([mgr removeFileAtPath: _lockPath handler: nil] == NO)
 
78
        {
 
79
          const char    *err = GSLastErrorStr(errno);
 
80
 
 
81
          attributes = [mgr fileAttributesAtPath: _lockPath traverseLink: YES];
 
82
          if ([modDate isEqual: [attributes fileModificationDate]] == YES)
 
83
            {
 
84
              [NSException raise: NSGenericException
 
85
                      format: @"Failed to remove lock directory '%@' - %s",
 
86
                      _lockPath, err];
 
87
            }
 
88
        }
 
89
    }
55
90
}
56
91
 
57
92
- (void) dealloc
61
96
  [super dealloc];
62
97
}
63
98
 
64
 
- (NSDistributedLock*) initWithPath: (NSString*)aPath
 
99
/**
 
100
 * Initialises the reciever with the specified filesystem path.<br />
 
101
 * The location in the filesystem must be accessible for this
 
102
 * to be usable.  That is, the processes using the lock must be able
 
103
 * to access, create, and destroy files at the path.<br />
 
104
 * The directory in which the last path component resides must already
 
105
 * exist ... create it using NSFileManager if you need to.
 
106
 */
 
107
- (id) initWithPath: (NSString*)aPath
65
108
{
66
 
  NSFileManager *fileManager;
67
109
  NSString      *lockDir;
68
110
  BOOL          isDirectory;
69
111
 
70
112
  _lockPath = [aPath copy];
71
113
  _lockTime = nil;
72
114
 
73
 
  fileManager = [NSFileManager defaultManager];
74
115
  lockDir = [_lockPath stringByDeletingLastPathComponent];
75
 
  if ([fileManager fileExistsAtPath: lockDir isDirectory: &isDirectory] == NO)
 
116
  if ([mgr fileExistsAtPath: lockDir isDirectory: &isDirectory] == NO)
76
117
    {
77
118
      NSLog(@"part of the path to the lock file '%@' is missing\n", _lockPath);
78
119
      RELEASE(self);
85
126
      RELEASE(self);
86
127
      return nil;
87
128
    }
88
 
  if ([fileManager isWritableFileAtPath: lockDir] == NO)
 
129
  if ([mgr isWritableFileAtPath: lockDir] == NO)
89
130
    {
90
131
      NSLog(@"parent directory of lock file '%@' is not writable\n", _lockPath);
91
132
      RELEASE(self);
92
133
      return nil;
93
134
    }
94
 
  if ([fileManager isExecutableFileAtPath: lockDir] == NO)
 
135
  if ([mgr isExecutableFileAtPath: lockDir] == NO)
95
136
    {
96
137
      NSLog(@"parent directory of lock file '%@' is not accessible\n",
97
138
                _lockPath);
101
142
  return self;
102
143
}
103
144
 
 
145
/**
 
146
 * Returns the date at which the lock was aquired by <em>any</em>
 
147
 * NSDistributedLock using the same path.  If nothing has
 
148
 * the lock, this returns nil.
 
149
 */
104
150
- (NSDate*) lockDate
105
151
{
106
 
  NSFileManager *fileManager;
107
152
  NSDictionary  *attributes;
108
153
 
109
 
  fileManager = [NSFileManager defaultManager];
110
 
  attributes = [fileManager fileAttributesAtPath: _lockPath traverseLink: YES];
111
 
  return [attributes objectForKey: NSFileModificationDate];
 
154
  attributes = [mgr fileAttributesAtPath: _lockPath traverseLink: YES];
 
155
  return [attributes fileModificationDate];
112
156
}
113
157
 
 
158
/**
 
159
 * Attempt to aquire the lock and return YES on success, NO on failure.<br />
 
160
 * May raise an NSGenericException if a problem occurs.
 
161
 */
114
162
- (BOOL) tryLock
115
163
{
116
 
  NSFileManager         *fileManager;
117
164
  NSMutableDictionary   *attributesToSet;
118
165
  NSDictionary          *attributes;
119
166
  BOOL                  locked;
120
167
 
121
 
  fileManager = [NSFileManager defaultManager];
122
168
  attributesToSet = [NSMutableDictionary dictionaryWithCapacity: 1];
123
169
  [attributesToSet setObject: [NSNumber numberWithUnsignedInt: 0755]
124
170
                      forKey: NSFilePosixPermissions];
125
171
        
126
 
  locked = [fileManager createDirectoryAtPath: _lockPath
127
 
                                   attributes: attributesToSet];
 
172
  locked = [mgr createDirectoryAtPath: _lockPath
 
173
                           attributes: attributesToSet];
128
174
  if (locked == NO)
129
175
    {
130
176
      BOOL      dir;
135
181
       * then either the other process has removed it's lock (and we can retry)
136
182
       * or we have a severe problem!
137
183
       */
138
 
      if ([fileManager fileExistsAtPath: _lockPath isDirectory: &dir] == NO)
 
184
      if ([mgr fileExistsAtPath: _lockPath isDirectory: &dir] == NO)
139
185
        {
140
 
          locked = [fileManager createDirectoryAtPath: _lockPath
141
 
                                           attributes: attributesToSet];
 
186
          locked = [mgr createDirectoryAtPath: _lockPath
 
187
                                   attributes: attributesToSet];
142
188
          if (locked == NO)
143
189
            {
144
190
              NSLog(@"Failed to create lock directory '%@' - %s",
149
195
 
150
196
  if (locked == NO)
151
197
    {
152
 
      RELEASE(_lockTime);
153
 
      _lockTime = nil;
154
198
      return NO;
155
199
    }
156
200
  else
157
201
    {
158
 
      attributes = [fileManager fileAttributesAtPath: _lockPath
159
 
                                        traverseLink: YES];
160
 
      RELEASE(_lockTime);
161
 
      _lockTime = RETAIN([attributes objectForKey: NSFileModificationDate]);
 
202
      attributes = [mgr fileAttributesAtPath: _lockPath
 
203
                                traverseLink: YES];
 
204
      if (attributes == nil)
 
205
        {
 
206
          [NSException raise: NSGenericException
 
207
                      format: @"Unable to get attributes of lock file we made"];
 
208
        }
 
209
      ASSIGN(_lockTime, [attributes fileModificationDate]);
162
210
      return YES;
163
211
    }
164
212
}
165
213
 
 
214
/**
 
215
 * Releases the lock.  Raises an NSGenericException if unable to release
 
216
 * the lock (for instance if the receiver does not own it or another
 
217
 * process has broken it).
 
218
 */
166
219
- (void) unlock
167
220
{
168
 
  NSFileManager *fileManager;
169
221
  NSDictionary  *attributes;
170
222
 
171
223
  if (_lockTime == nil)
172
 
    [NSException raise: NSGenericException format: @"not locked by us"];
 
224
    {
 
225
      [NSException raise: NSGenericException format: @"not locked by us"];
 
226
    }
173
227
 
174
228
  /*
175
229
   *    Don't remove the lock if it has already been broken by someone
176
230
   *    else and re-created.  Unfortunately, there is a window between
177
231
   *    testing and removing, but we do the bset we can.
178
232
   */
179
 
  fileManager = [NSFileManager defaultManager];
180
 
  attributes = [fileManager fileAttributesAtPath: _lockPath traverseLink: YES];
181
 
  if ([_lockTime isEqual: [attributes objectForKey: NSFileModificationDate]])
182
 
    {
183
 
      if ([fileManager removeFileAtPath: _lockPath handler: nil] == NO)
184
 
        [NSException raise: NSGenericException
185
 
                    format: @"Failed to remove lock directory '%@' - %s",
186
 
                        _lockPath, GSLastErrorStr(errno)];
 
233
  attributes = [mgr fileAttributesAtPath: _lockPath traverseLink: YES];
 
234
  if (attributes == nil)
 
235
    {
 
236
      DESTROY(_lockTime);
 
237
      [NSException raise: NSGenericException
 
238
                  format: @"lock '%@' already broken", _lockPath];
 
239
    }
 
240
  if ([_lockTime isEqual: [attributes fileModificationDate]])
 
241
    {
 
242
      DESTROY(_lockTime);
 
243
      if ([mgr removeFileAtPath: _lockPath handler: nil] == NO)
 
244
        {
 
245
          [NSException raise: NSGenericException
 
246
                      format: @"Failed to remove lock directory '%@' - %s",
 
247
                          _lockPath, GSLastErrorStr(errno)];
 
248
        }
187
249
    }
188
250
  else
189
 
    NSLog(@"lock '%@' already broken and in use again\n", _lockPath);
190
 
 
191
 
  RELEASE(_lockTime);
192
 
  _lockTime = nil;
 
251
    {
 
252
      DESTROY(_lockTime);
 
253
      [NSException raise: NSGenericException
 
254
                  format: @"lock '%@' already broken and in use again",
 
255
        _lockPath];
 
256
    }
 
257
  DESTROY(_lockTime);
193
258
}
194
259
 
195
260
@end