Small cleanup of extensions code
[AROS.git] / compiler / clib / flock.c
blob8094c18bdf2b175f96d75aed605f72611792fb1c
1 /*
2 Copyright © 2008, The AROS Development Team. All rights reserved.
3 $Id$
5 4.4BSD function flock().
6 */
8 #define DEBUG 0
10 #include <proto/exec.h>
11 #include <exec/exec.h>
12 #include <proto/dos.h>
13 #include <dos/dos.h>
14 #include <aros/debug.h>
15 #include <aros/startup.h>
16 #include <aros/symbolsets.h>
18 #include <errno.h>
20 #include "__open.h"
21 #include "__errno.h"
22 #include "__arosc_privdata.h"
24 struct FlockNode
26 struct Node node;
27 struct SignalSemaphore *sem;
30 LONG AddToList(struct SignalSemaphore *sem);
31 void RemoveFromList(struct SignalSemaphore *sem);
33 /*****************************************************************************
35 NAME */
36 #include <sys/file.h>
38 int flock (
40 /* SYNOPSIS */
41 int fd,
42 int operation)
44 /* FUNCTION
45 Apply or remove an advisory lock on open file descriptor fd. Operation
46 argument can be one of the following constants:
48 LOCK_SH - Place a shared lock on the file specified by fd. More that
49 one process can hold a shared lock on a given file at a
50 time.
52 LOCK_EX - Place an exclusive lock on the file specified by fd. Only
53 one process can hold an exclusive lock on a given file at
54 a time.
56 LOCK_UN - Remove an existing lock from the file specified by fd.
58 LOCK_EX operation blocks if there is a lock already placed on the
59 file. LOCK_SH blocks if there is an exclusive lock already placed
60 on the file. If you want to do a non-blocking request, OR the
61 operation specifier with LOCK_NB constant. In this case flock() will
62 return -1 instead of blocking and set errno to EWOULDBLOCK.
64 Advisory locks created with flock() are shared among duplicated file
65 descriptors.
67 INPUTS
68 fd - File descriptor of the file you want to place or remove lock from.
69 operation - Lock operation to be performed.
71 RESULT
72 0 on success, -1 on error. In case of error a global errno variable
73 is set.
75 NOTES
76 Locks placed with flock() are only advisory, they place no
77 restrictions to any file or file descriptor operations.
79 EXAMPLE
81 BUGS
82 It's currently possible to remove lock placed by another process.
84 SEE ALSO
86 INTERNALS
87 Since advisory locks semantics is equal to exec.library semaphores
88 semantics, semaphores are used to implement locks. For a given file
89 a semaphore named FLOCK(path) is created where path is a full path to
90 the file. Locks held by a given process are stored on __flocks_list
91 and released during process exit.
93 ******************************************************************************/
95 fdesc *fdesc = __getfdesc(fd);
96 char *buffer;
97 int buffersize = 256;
98 struct SignalSemaphore *sem;
100 D(bug("flock(%d, %d)\n", fd, operation));
101 if (!fdesc)
103 errno = EBADF;
104 return -1;
107 /* Sanity check */
109 (operation & ~LOCK_NB) != LOCK_SH &&
110 (operation & ~LOCK_NB) != LOCK_EX &&
111 (operation & ~LOCK_NB) != LOCK_UN
114 errno = EINVAL;
115 return -1;
118 /* Get the full path of the flocked filesystem object */
121 if(!(buffer = AllocVec(buffersize, MEMF_ANY)))
123 errno = IoErr2errno(IoErr());
124 return -1;
127 if(NameFromLock(fdesc->fcb->fh, (STRPTR) ((IPTR) buffer + 6), buffersize - 7))
128 break;
129 else if(IoErr() != ERROR_LINE_TOO_LONG)
131 errno = IoErr2errno(IoErr());
132 FreeVec(buffer);
133 return -1;
135 FreeVec(buffer);
136 buffersize *= 2;
138 while(TRUE);
140 CopyMem("FLOCK(", buffer, strlen("FLOCK("));
141 buffer[strlen(buffer) + 1] = '\0';
142 buffer[strlen(buffer)] = ')';
144 D(bug("[flock] Semaphore name: %s\n", buffer));
146 /* Find semaphore named FLOCK(path), add a new one if not found any */
147 Forbid();
148 sem = FindSemaphore((STRPTR) buffer);
149 if(!sem)
151 D(bug("[flock] Semaphore %s not found, creating a new one\n", buffer));
152 sem = (struct SignalSemaphore*)
153 AllocVec(sizeof(struct SignalSemaphore), MEMF_PUBLIC|MEMF_CLEAR);
154 if(!sem)
156 errno = ENOMEM;
157 Permit();
158 return -1;
160 sem->ss_Link.ln_Name = buffer;
161 AddSemaphore(sem);
163 else
165 D(bug("[flock] Semaphore %s found, freeing buffer\n", buffer));
166 FreeVec(buffer);
169 if(operation & LOCK_UN)
171 D(bug("[flock] Releasing semaphore %s\n", sem->ss_Link.ln_Name));
172 ReleaseSemaphore(sem);
173 RemoveFromList(sem);
174 if(sem->ss_Owner == NULL && sem->ss_QueueCount == -1)
176 D(bug("[flock] All locks unlocked, removing semaphore %s\n", sem->ss_Link.ln_Name));
177 /* All locks for this file were unlocked, we don't need semaphore
178 * anymore */
179 RemSemaphore(sem);
180 FreeVec(sem->ss_Link.ln_Name);
181 FreeVec(sem);
182 Permit();
183 return 0;
186 Permit();
188 switch(operation & ~LOCK_NB)
190 case LOCK_SH:
191 D(bug("[flock] Obtaining shared lock\n"));
192 if(operation & LOCK_NB)
194 if(!AttemptSemaphoreShared(sem))
196 errno = EWOULDBLOCK;
197 return -1;
200 else
201 ObtainSemaphoreShared(sem);
202 D(bug("[flock] Shared lock obtained\n"));
203 AddToList(sem);
204 break;
205 case LOCK_EX:
206 D(bug("[flock] Obtaining exclusive lock\n"));
207 if(operation & LOCK_NB)
209 if(!AttemptSemaphore(sem))
211 errno = EWOULDBLOCK;
212 return -1;
215 else
216 ObtainSemaphore(sem);
217 D(bug("[flock] Exclusive lock obtained\n"));
218 AddToList(sem);
219 break;
221 return 0;
224 LONG AddToList(struct SignalSemaphore *sem)
226 struct FlockNode *node;
227 node = AllocMem(sizeof(struct FlockNode), MEMF_ANY | MEMF_CLEAR);
228 if(!node)
229 return -1;
230 node->sem = sem;
231 AddHead((struct List *)&__flocks_list, (struct Node*) node);
232 return 0;
235 void RemoveFromList(struct SignalSemaphore *sem)
237 struct FlockNode *varNode;
238 struct Node *tmpNode;
240 ForeachNodeSafe(&__flocks_list, varNode, tmpNode)
242 if(varNode->sem == sem)
244 Remove((struct Node*) varNode);
245 FreeMem(varNode, sizeof(struct FlockNode));
246 break;
251 int __init_flocks(void)
253 NEWLIST((struct List *)&__flocks_list);
255 return 1;
258 void __unlock_flocks(void)
261 struct FlockNode *lock;
262 struct SignalSemaphore *sem;
264 Forbid();
265 while ((lock = (struct FlockNode *) REMHEAD(
266 (struct List *) &__flocks_list)))
268 sem = lock->sem;
269 ReleaseSemaphore(sem);
270 FreeMem(lock, sizeof(struct FlockNode));
272 if(sem->ss_Owner == NULL && sem->ss_QueueCount == -1)
274 D(bug("[flock] All locks unlocked, removing semaphore %s\n", sem->ss_Link.ln_Name));
275 /* All locks for this file were unlocked, we don't need semaphore
276 * anymore */
277 RemSemaphore(sem);
278 FreeVec(sem->ss_Link.ln_Name);
279 FreeVec(sem);
282 Permit();
286 ADD2INIT(__init_flocks, 1);
287 ADD2EXIT(__unlock_flocks, 1);