2 Copyright © 2008-2012, The AROS Development Team. All rights reserved.
5 4.4BSD function flock().
9 #include <proto/exec.h>
10 #include <exec/exec.h>
11 #include <proto/dos.h>
13 #include <aros/debug.h>
14 #include <aros/symbolsets.h>
19 #include "__arosc_privdata.h"
24 struct SignalSemaphore
*sem
;
27 LONG
AddToList(struct SignalSemaphore
*sem
);
28 void RemoveFromList(struct SignalSemaphore
*sem
);
30 /*****************************************************************************
42 Apply or remove an advisory lock on open file descriptor fd. Operation
43 argument can be one of the following constants:
45 LOCK_SH - Place a shared lock on the file specified by fd. More that
46 one process can hold a shared lock on a given file at a
49 LOCK_EX - Place an exclusive lock on the file specified by fd. Only
50 one process can hold an exclusive lock on a given file at
53 LOCK_UN - Remove an existing lock from the file specified by fd.
55 LOCK_EX operation blocks if there is a lock already placed on the
56 file. LOCK_SH blocks if there is an exclusive lock already placed
57 on the file. If you want to do a non-blocking request, OR the
58 operation specifier with LOCK_NB constant. In this case flock() will
59 return -1 instead of blocking and set errno to EWOULDBLOCK.
61 Advisory locks created with flock() are shared among duplicated file
65 fd - File descriptor of the file you want to place or remove lock from.
66 operation - Lock operation to be performed.
69 0 on success, -1 on error. In case of error a global errno variable
73 Locks placed with flock() are only advisory, they place no
74 restrictions to any file or file descriptor operations.
79 It's currently possible to remove lock placed by another process.
84 Since advisory locks semantics is equal to exec.library semaphores
85 semantics, semaphores are used to implement locks. For a given file
86 a semaphore named FLOCK(path) is created where path is a full path to
87 the file. Locks held by a given process are stored on aroscbase->acb_file_locks
88 and released during process exit.
90 ******************************************************************************/
92 fdesc
*fdesc
= __getfdesc(fd
);
95 struct SignalSemaphore
*sem
;
97 D(bug("flock(%d, %d)\n", fd
, operation
));
106 (operation
& ~LOCK_NB
) != LOCK_SH
&&
107 (operation
& ~LOCK_NB
) != LOCK_EX
&&
108 (operation
& ~LOCK_NB
) != LOCK_UN
115 /* Get the full path of the flocked filesystem object */
118 if(!(buffer
= AllocVec(buffersize
, MEMF_ANY
)))
120 errno
= __arosc_ioerr2errno(IoErr());
124 if(NameFromFH(fdesc
->fcb
->fh
, (STRPTR
) ((IPTR
) buffer
+ 6), buffersize
- 7))
126 else if(IoErr() != ERROR_LINE_TOO_LONG
)
128 errno
= __arosc_ioerr2errno(IoErr());
137 CopyMem("FLOCK(", buffer
, strlen("FLOCK("));
138 buffer
[strlen(buffer
) + 1] = '\0';
139 buffer
[strlen(buffer
)] = ')';
141 D(bug("[flock] Semaphore name: %s\n", buffer
));
143 /* Find semaphore named FLOCK(path), add a new one if not found any */
145 sem
= FindSemaphore((STRPTR
) buffer
);
148 D(bug("[flock] Semaphore %s not found, creating a new one\n", buffer
));
149 sem
= (struct SignalSemaphore
*)
150 AllocVec(sizeof(struct SignalSemaphore
), MEMF_PUBLIC
|MEMF_CLEAR
);
157 sem
->ss_Link
.ln_Name
= buffer
;
162 D(bug("[flock] Semaphore %s found, freeing buffer\n", buffer
));
166 if(operation
& LOCK_UN
)
168 D(bug("[flock] Releasing semaphore %s\n", sem
->ss_Link
.ln_Name
));
169 ReleaseSemaphore(sem
);
171 if(sem
->ss_Owner
== NULL
&& sem
->ss_QueueCount
== -1)
173 D(bug("[flock] All locks unlocked, removing semaphore %s\n", sem
->ss_Link
.ln_Name
));
174 /* All locks for this file were unlocked, we don't need semaphore
177 FreeVec(sem
->ss_Link
.ln_Name
);
185 switch(operation
& ~LOCK_NB
)
188 D(bug("[flock] Obtaining shared lock\n"));
189 if(operation
& LOCK_NB
)
191 if(!AttemptSemaphoreShared(sem
))
198 ObtainSemaphoreShared(sem
);
199 D(bug("[flock] Shared lock obtained\n"));
203 D(bug("[flock] Obtaining exclusive lock\n"));
204 if(operation
& LOCK_NB
)
206 if(!AttemptSemaphore(sem
))
213 ObtainSemaphore(sem
);
214 D(bug("[flock] Exclusive lock obtained\n"));
221 LONG
AddToList(struct SignalSemaphore
*sem
)
223 struct aroscbase
*aroscbase
= __aros_getbase_aroscbase();
224 struct FlockNode
*node
;
225 node
= AllocMem(sizeof(struct FlockNode
), MEMF_ANY
| MEMF_CLEAR
);
229 AddHead(aroscbase
->acb_file_locks
, (struct Node
*) node
);
233 void RemoveFromList(struct SignalSemaphore
*sem
)
235 struct aroscbase
*aroscbase
= __aros_getbase_aroscbase();
236 struct FlockNode
*varNode
;
237 struct Node
*tmpNode
;
239 ForeachNodeSafe(aroscbase
->acb_file_locks
, varNode
, tmpNode
)
241 if(varNode
->sem
== sem
)
243 Remove((struct Node
*) varNode
);
244 FreeMem(varNode
, sizeof(struct FlockNode
));
250 /* __init_flocks is called during library init.
251 aroscbase->acb_file_locks will be initialized here and then copied
252 in all libbases for each open of the library.
253 This means that a global file_locks list is used, this is needed as flocks
254 are used for locking between different processes.
256 int __init_flocks(struct aroscbase
*base
)
258 base
->acb_file_locks
= AllocMem(sizeof(struct MinList
), MEMF_PUBLIC
);
259 NEWLIST(base
->acb_file_locks
);
261 D(bug("[flock] Initialized lock list at 0x%p\n", base
->acb_file_locks
));
266 /* This function is called once before root libbase would be freed.
267 This function will be called when no other program has arosc.library open
268 so no protection should be needed.
270 void __unlock_flocks(struct aroscbase
*base
)
272 struct FlockNode
*lock
;
273 struct SignalSemaphore
*sem
;
275 D(bug("[flock] Freeing lock list at 0x%p\n", base
->acb_file_locks
));
277 while ((lock
= (struct FlockNode
*) REMHEAD(base
->acb_file_locks
)))
280 ReleaseSemaphore(sem
);
281 FreeMem(lock
, sizeof(struct FlockNode
));
283 if (sem
->ss_Owner
!= NULL
|| sem
->ss_QueueCount
!= -1)
284 bug("[flock] Freeing locked semaphore!");
286 D(bug("[flock] removing semaphore %s\n", sem
->ss_Link
.ln_Name
));
288 FreeVec(sem
->ss_Link
.ln_Name
);
291 FreeMem(base
->acb_file_locks
, sizeof(struct MinList
));
292 base
->acb_file_locks
= NULL
;
295 ADD2INITLIB(__init_flocks
, 1);
296 ADD2EXPUNGELIB(__unlock_flocks
, 1);