2 Copyright © 2008-2016, 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 "__posixc_intbase.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 in
88 PosixCBase->file_locks 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
= __stdc_ioerr2errno(IoErr());
124 if(NameFromFH(fdesc
->fcb
->handle
, (STRPTR
) ((IPTR
) buffer
+ 6), buffersize
- 7))
126 else if(IoErr() != ERROR_LINE_TOO_LONG
)
128 errno
= __stdc_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 PosixCIntBase
*PosixCBase
=
224 (struct PosixCIntBase
*)__aros_getbase_PosixCBase();
225 struct FlockNode
*node
;
226 node
= AllocMem(sizeof(struct FlockNode
), MEMF_ANY
| MEMF_CLEAR
);
230 AddHead((struct List
*)PosixCBase
->file_locks
, (struct Node
*) node
);
234 void RemoveFromList(struct SignalSemaphore
*sem
)
236 struct PosixCIntBase
*PosixCBase
=
237 (struct PosixCIntBase
*)__aros_getbase_PosixCBase();
238 struct FlockNode
*varNode
;
239 struct Node
*tmpNode
;
241 ForeachNodeSafe(PosixCBase
->file_locks
, varNode
, tmpNode
)
243 if(varNode
->sem
== sem
)
245 Remove((struct Node
*) varNode
);
246 FreeMem(varNode
, sizeof(struct FlockNode
));
252 /* __init_flocks is called during library init.
253 PosixCBase->file_locks will be initialized here and then copied
254 in all libbases for each open of the library.
255 This means that a global file_locks list is used, this is needed as flocks
256 are used for locking between different processes.
258 int __init_flocks(struct PosixCIntBase
*PosixCBase
)
260 PosixCBase
->file_locks
= AllocMem(sizeof(struct MinList
), MEMF_PUBLIC
);
261 NEWLIST(PosixCBase
->file_locks
);
263 D(bug("[flock] Initialized lock list at 0x%p\n", PosixCBase
->file_locks
));
268 /* This function is called once before root libbase would be freed.
269 This function will be called when no other program has posixc.library open
270 so no protection should be needed.
272 void __unlock_flocks(struct PosixCIntBase
*PosixCBase
)
274 struct FlockNode
*lock
;
275 struct SignalSemaphore
*sem
;
277 D(bug("[flock] Freeing lock list at 0x%p\n", PosixCBase
->file_locks
));
279 while ((lock
= (struct FlockNode
*) REMHEAD(PosixCBase
->file_locks
)))
282 ReleaseSemaphore(sem
);
283 FreeMem(lock
, sizeof(struct FlockNode
));
285 if (sem
->ss_Owner
!= NULL
|| sem
->ss_QueueCount
!= -1)
286 bug("[flock] Freeing locked semaphore!");
288 D(bug("[flock] removing semaphore %s\n", sem
->ss_Link
.ln_Name
));
290 FreeVec(sem
->ss_Link
.ln_Name
);
293 FreeMem(PosixCBase
->file_locks
, sizeof(struct MinList
));
294 PosixCBase
->file_locks
= NULL
;
297 ADD2INITLIB(__init_flocks
, 1);
298 ADD2EXPUNGELIB(__unlock_flocks
, 1);