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/startup.h>
15 #include <aros/symbolsets.h>
21 #include "__arosc_privdata.h"
26 struct SignalSemaphore
*sem
;
29 LONG
AddToList(struct SignalSemaphore
*sem
);
30 void RemoveFromList(struct SignalSemaphore
*sem
);
32 /*****************************************************************************
44 Apply or remove an advisory lock on open file descriptor fd. Operation
45 argument can be one of the following constants:
47 LOCK_SH - Place a shared lock on the file specified by fd. More that
48 one process can hold a shared lock on a given file at a
51 LOCK_EX - Place an exclusive lock on the file specified by fd. Only
52 one process can hold an exclusive lock on a given file at
55 LOCK_UN - Remove an existing lock from the file specified by fd.
57 LOCK_EX operation blocks if there is a lock already placed on the
58 file. LOCK_SH blocks if there is an exclusive lock already placed
59 on the file. If you want to do a non-blocking request, OR the
60 operation specifier with LOCK_NB constant. In this case flock() will
61 return -1 instead of blocking and set errno to EWOULDBLOCK.
63 Advisory locks created with flock() are shared among duplicated file
67 fd - File descriptor of the file you want to place or remove lock from.
68 operation - Lock operation to be performed.
71 0 on success, -1 on error. In case of error a global errno variable
75 Locks placed with flock() are only advisory, they place no
76 restrictions to any file or file descriptor operations.
81 It's currently possible to remove lock placed by another process.
86 Since advisory locks semantics is equal to exec.library semaphores
87 semantics, semaphores are used to implement locks. For a given file
88 a semaphore named FLOCK(path) is created where path is a full path to
89 the file. Locks held by a given process are stored on aroscbase->acb_file_locks
90 and released during process exit.
92 ******************************************************************************/
94 fdesc
*fdesc
= __getfdesc(fd
);
97 struct SignalSemaphore
*sem
;
99 D(bug("flock(%d, %d)\n", fd
, operation
));
108 (operation
& ~LOCK_NB
) != LOCK_SH
&&
109 (operation
& ~LOCK_NB
) != LOCK_EX
&&
110 (operation
& ~LOCK_NB
) != LOCK_UN
117 /* Get the full path of the flocked filesystem object */
120 if(!(buffer
= AllocVec(buffersize
, MEMF_ANY
)))
122 errno
= IoErr2errno(IoErr());
126 if(NameFromFH(fdesc
->fcb
->fh
, (STRPTR
) ((IPTR
) buffer
+ 6), buffersize
- 7))
128 else if(IoErr() != ERROR_LINE_TOO_LONG
)
130 errno
= IoErr2errno(IoErr());
139 CopyMem("FLOCK(", buffer
, strlen("FLOCK("));
140 buffer
[strlen(buffer
) + 1] = '\0';
141 buffer
[strlen(buffer
)] = ')';
143 D(bug("[flock] Semaphore name: %s\n", buffer
));
145 /* Find semaphore named FLOCK(path), add a new one if not found any */
147 sem
= FindSemaphore((STRPTR
) buffer
);
150 D(bug("[flock] Semaphore %s not found, creating a new one\n", buffer
));
151 sem
= (struct SignalSemaphore
*)
152 AllocVec(sizeof(struct SignalSemaphore
), MEMF_PUBLIC
|MEMF_CLEAR
);
159 sem
->ss_Link
.ln_Name
= buffer
;
164 D(bug("[flock] Semaphore %s found, freeing buffer\n", buffer
));
168 if(operation
& LOCK_UN
)
170 D(bug("[flock] Releasing semaphore %s\n", sem
->ss_Link
.ln_Name
));
171 ReleaseSemaphore(sem
);
173 if(sem
->ss_Owner
== NULL
&& sem
->ss_QueueCount
== -1)
175 D(bug("[flock] All locks unlocked, removing semaphore %s\n", sem
->ss_Link
.ln_Name
));
176 /* All locks for this file were unlocked, we don't need semaphore
179 FreeVec(sem
->ss_Link
.ln_Name
);
187 switch(operation
& ~LOCK_NB
)
190 D(bug("[flock] Obtaining shared lock\n"));
191 if(operation
& LOCK_NB
)
193 if(!AttemptSemaphoreShared(sem
))
200 ObtainSemaphoreShared(sem
);
201 D(bug("[flock] Shared lock obtained\n"));
205 D(bug("[flock] Obtaining exclusive lock\n"));
206 if(operation
& LOCK_NB
)
208 if(!AttemptSemaphore(sem
))
215 ObtainSemaphore(sem
);
216 D(bug("[flock] Exclusive lock obtained\n"));
223 LONG
AddToList(struct SignalSemaphore
*sem
)
225 struct aroscbase
*aroscbase
= __GM_GetBase();
226 struct FlockNode
*node
;
227 node
= AllocMem(sizeof(struct FlockNode
), MEMF_ANY
| MEMF_CLEAR
);
231 AddHead((struct List
*)&aroscbase
->acb_file_locks
, (struct Node
*) node
);
235 void RemoveFromList(struct SignalSemaphore
*sem
)
237 struct aroscbase
*aroscbase
= __GM_GetBase();
238 struct FlockNode
*varNode
;
239 struct Node
*tmpNode
;
241 ForeachNodeSafe(&aroscbase
->acb_file_locks
, varNode
, tmpNode
)
243 if(varNode
->sem
== sem
)
245 Remove((struct Node
*) varNode
);
246 FreeMem(varNode
, sizeof(struct FlockNode
));
252 int __init_flocks(struct aroscbase
*base
)
255 * This function is called once each time a new libbase is created
257 NEWLIST(&base
->acb_file_locks
);
259 D(bug("[flock] Initialized lock list at 0x%p\n", &base
->acb_file_locks
));
264 void __unlock_flocks(struct aroscbase
*base
)
266 /* This function is called once before libbase would be freed */
267 if (base
->acb_file_locks
.mlh_Head
)
269 struct FlockNode
*lock
;
270 struct SignalSemaphore
*sem
;
272 D(bug("[flock] Freeing lock list at 0x%p\n", &base
->acb_file_locks
));
274 while ((lock
= (struct FlockNode
*) REMHEAD(&base
->acb_file_locks
)))
277 ReleaseSemaphore(sem
);
278 FreeMem(lock
, sizeof(struct FlockNode
));
280 if(sem
->ss_Owner
== NULL
&& sem
->ss_QueueCount
== -1)
282 D(bug("[flock] All locks unlocked, removing semaphore %s\n", sem
->ss_Link
.ln_Name
));
283 /* All locks for this file were unlocked, we don't need semaphore
286 FreeVec(sem
->ss_Link
.ln_Name
);
293 ADD2OPENLIB(__init_flocks
, 1);
294 ADD2CLOSELIB(__unlock_flocks
, 1);