author | Alberto Bertogli
<albertogli@telpin.com.ar> 2005-04-15 05:22:25 UTC |
committer | Alberto Bertogli
<albertogli@telpin.com.ar> 2005-04-15 05:22:25 UTC |
LICENSE | +181 | -0 |
Makefile | +55 | -0 |
README | +4 | -0 |
libfilo.c | +456 | -0 |
libfilo.h | +60 | -0 |
diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..6cf9100 --- /dev/null +++ b/LICENSE @@ -0,0 +1,181 @@ + +This project, 'libfilo', is copyrighted by Alberto Bertogli and licensed under +the Open Software License version 2.1 as obtained from www.opensource.org (and +included here-in for easy reference) (that license itself is copyrighted by +Larry Rosen). + +Note that the "Original Work" that this license covers is only the library +itself. Thus just the act of linking/importing this library into another +program does NOT in itself make that program considered a derivative work of +this Original Work. + + Alberto Bertogli + 15 April 2005 + +------------------------------------------------------------------------- + + +Open Software License +v. 2.1 + +This Open Software License (the "License") applies to any original work of +authorship (the "Original Work") whose owner (the "Licensor") has placed the +following notice immediately following the copyright notice for the Original +Work: + +Licensed under the Open Software License version 2.1 + +1) Grant of Copyright License. Licensor hereby grants You a world-wide, +royalty-free, non-exclusive, perpetual, sublicenseable license to do the +following: + + * to reproduce the Original Work in copies; + * to prepare derivative works ("Derivative Works") based upon the Original Work; + * to distribute copies of the Original Work and Derivative Works to the + public, with the proviso that copies of Original Work or Derivative + Works that You distribute shall be licensed under the Open Software + License; + * to perform the Original Work publicly; and + * to display the Original Work publicly. + +2) Grant of Patent License. Licensor hereby grants You a world-wide, +royalty-free, non-exclusive, perpetual, sublicenseable license, under patent +claims owned or controlled by the Licensor that are embodied in the Original +Work as furnished by the Licensor, to make, use, sell and offer for sale the +Original Work and Derivative Works. + +3) Grant of Source Code License. The term "Source Code" means the preferred +form of the Original Work for making modifications to it and all available +documentation describing how to modify the Original Work. Licensor hereby +agrees to provide a machine-readable copy of the Source Code of the Original +Work along with each copy of the Original Work that Licensor distributes. +Licensor reserves the right to satisfy this obligation by placing a +machine-readable copy of the Source Code in an information repository +reasonably calculated to permit inexpensive and convenient access by You for +as long as Licensor continues to distribute the Original Work, and by +publishing the address of that information repository in a notice immediately +following the copyright notice that applies to the Original Work. + +4) Exclusions From License Grant. Neither the names of Licensor, nor the names +of any contributors to the Original Work, nor any of their trademarks or +service marks, may be used to endorse or promote products derived from this +Original Work without express prior written permission of the Licensor. +Nothing in this License shall be deemed to grant any rights to trademarks, +copyrights, patents, trade secrets or any other intellectual property of +Licensor except as expressly stated herein. No patent license is granted to +make, use, sell or offer to sell embodiments of any patent claims other than +the licensed claims defined in Section 2. No right is granted to the +trademarks of Licensor even if such marks are included in the Original Work. +Nothing in this License shall be interpreted to prohibit Licensor from +licensing under different terms from this License any Original Work that +Licensor otherwise would have a right to license. + +5) External Deployment. The term "External Deployment" means the use or +distribution of the Original Work or Derivative Works in any way such that the +Original Work or Derivative Works may be used by anyone other than You, +whether the Original Work or Derivative Works are distributed to those persons +or made available as an application intended for use over a computer network. +As an express condition for the grants of license hereunder, You agree that +any External Deployment by You of a Derivative Work shall be deemed a +distribution and shall be licensed to all under the terms of this License, as +prescribed in section 1(c) herein. + +6) Attribution Rights. You must retain, in the Source Code of any Derivative +Works that You create, all copyright, patent or trademark notices from the +Source Code of the Original Work, as well as any notices of licensing and any +descriptive text identified therein as an "Attribution Notice." You must cause +the Source Code for any Derivative Works that You create to carry a prominent +Attribution Notice reasonably calculated to inform recipients that You have +modified the Original Work. + +7) Warranty of Provenance and Disclaimer of Warranty. Licensor warrants that +the copyright in and to the Original Work and the patent rights granted herein +by Licensor are owned by the Licensor or are sublicensed to You under the +terms of this License with the permission of the contributor(s) of those +copyrights and patent rights. Except as expressly stated in the immediately +proceeding sentence, the Original Work is provided under this License on an +"AS IS" BASIS and WITHOUT WARRANTY, either express or implied, including, +without limitation, the warranties of NON-INFRINGEMENT, MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY OF THE +ORIGINAL WORK IS WITH YOU. This DISCLAIMER OF WARRANTY constitutes an +essential part of this License. No license to Original Work is granted +hereunder except under this disclaimer. + +8) Limitation of Liability. Under no circumstances and under no legal theory, +whether in tort (including negligence), contract, or otherwise, shall the +Licensor be liable to any person for any direct, indirect, special, +incidental, or consequential damages of any character arising as a result of +this License or the use of the Original Work including, without limitation, +damages for loss of goodwill, work stoppage, computer failure or malfunction, +or any and all other commercial damages or losses. This limitation of +liability shall not apply to liability for death or personal injury resulting +from Licensor's negligence to the extent applicable law prohibits such +limitation. Some jurisdictions do not allow the exclusion or limitation of +incidental or consequential damages, so this exclusion and limitation may not +apply to You. + +9) Acceptance and Termination. If You distribute copies of the Original Work +or a Derivative Work, You must make a reasonable effort under the +circumstances to obtain the express assent of recipients to the terms of this +License. Nothing else but this License (or another written agreement between +Licensor and You) grants You permission to create Derivative Works based upon +the Original Work or to exercise any of the rights granted in Section 1 +herein, and any attempt to do so except under the terms of this License (or +another written agreement between Licensor and You) is expressly prohibited by +U.S. copyright law, the equivalent laws of other countries, and by +international treaty. Therefore, by exercising any of the rights granted to +You in Section 1 herein, You indicate Your acceptance of this License and all +of its terms and conditions. This License shall terminate immediately and you +may no longer exercise any of the rights granted to You by this License upon +Your failure to honor the proviso in Section 1(c) herein. + +10) Termination for Patent Action. This License shall terminate automatically +and You may no longer exercise any of the rights granted to You by this +License as of the date You commence an action, including a cross-claim or +counterclaim, against Licensor or any licensee alleging that the Original Work +infringes a patent. This termination provision shall not apply for an action +alleging patent infringement by combinations of the Original Work with other +software or hardware. + +11) Jurisdiction, Venue and Governing Law. Any action or suit relating to this +License may be brought only in the courts of a jurisdiction wherein the +Licensor resides or in which Licensor conducts its primary business, and under +the laws of that jurisdiction excluding its conflict-of-law provisions. The +application of the United Nations Convention on Contracts for the +International Sale of Goods is expressly excluded. Any use of the Original +Work outside the scope of this License or after its termination shall be +subject to the requirements and penalties of the U.S. Copyright Act, 17 U.S.C. +§ 101 et seq., the equivalent laws of other countries, and international +treaty. This section shall survive the termination of this License. + +12) Attorneys Fees. In any action to enforce the terms of this License or +seeking damages relating thereto, the prevailing party shall be entitled to +recover its costs and expenses, including, without limitation, reasonable +attorneys' fees and costs incurred in connection with such action, including +any appeal of such action. This section shall survive the termination of this +License. + +13) Miscellaneous. This License represents the complete agreement concerning +the subject matter hereof. If any provision of this License is held to be +unenforceable, such provision shall be reformed only to the extent necessary +to make it enforceable. + +14) Definition of "You" in This License. "You" throughout this License, +whether in upper or lower case, means an individual or a legal entity +exercising rights under, and complying with all of the terms of, this License. +For legal entities, "You" includes any entity that controls, is controlled by, +or is under common control with you. For purposes of this definition, +"control" means (i) the power, direct or indirect, to cause the direction or +management of such entity, whether by contract or otherwise, or (ii) ownership +of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial +ownership of such entity. + +15) Right to Use. You may use the Original Work in all ways not otherwise +restricted or conditioned by this License or by law, and Licensor promises not +to interfere with or be responsible for such uses by You. + +This license is Copyright (C) 2003-2004 Lawrence E. Rosen. All rights +reserved. Permission is hereby granted to copy and distribute this license +without modification. This license may not be modified without the express +written permission of its copyright owner. + diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..130994b --- /dev/null +++ b/Makefile @@ -0,0 +1,55 @@ + + +CFLAGS += -Wall -D_XOPEN_SOURCE=500 + +ifdef DEBUG + CFLAGS += -g -pg -fprofile-arcs -ftest-coverage +endif + +ifdef STRICT +CFLAGS += -ansi -pedantic +endif + +# prefix for installing the binaries +PREFIX=/usr/local + + +OBJS = libfilo.o + +default: all + +all: libfilo.so libfilo.a + +libfilo.so: $(OBJS) + $(CC) -shared -fPIC $(OBJS) -o libfilo.so + +libfilo.a: $(OBJS) + $(AR) cr libfilo.a $(OBJS) + +install: all + install -d $(PREFIX)/lib + install -m 0755 libfilo.so $(PREFIX)/lib + install -m 0644 libfilo.a $(PREFIX)/lib + install -d $(PREFIX)/include + install -m 0644 libfilo.h $(PREFIX)/include + @echo + @echo "Please run ldconfig to update your library cache" + @echo + +.c.o: + $(CC) $(CFLAGS) $(INCLUDES) -c $< -o $@ + +python: + cd python && python setup.py build + +python_install: + cd python && python setup.py install + +clean: + rm -f $(OBJS) libfilo.a libfilo.so + rm -f *.bb *.bbg *.da *.gcov gmon.out + rm -rf python/build + + +.PHONY: default all install python python_install clean + diff --git a/README b/README new file mode 100644 index 0000000..beeda86 --- /dev/null +++ b/README @@ -0,0 +1,4 @@ + +Questions or complaints about the name are responsability of Luca +(luca@llucax.hn.org). + diff --git a/libfilo.c b/libfilo.c new file mode 100644 index 0000000..084c47b --- /dev/null +++ b/libfilo.c @@ -0,0 +1,456 @@ + +/* + * libfilo - A File Locking Library + * Alberto Bertogli (albertogli@telpin.com.ar) + */ + + +#include <sys/types.h> /* for off_t */ +#include <pthread.h> /* for mutexes */ +#include <semaphore.h> /* for semaphores (duh!) */ +#include <stdlib.h> /* for malloc()/free() */ +#include "libfilo.h" + + +/* We have two lists for each file lock: one of currently locked portions of + * the file (a portion can have more than one read lock at the same time, but + * only one write lock), and another one with the current waiters for the + * lock. + * FIXME: document this. everything. + */ + +#if 0 /* XXX: debug */ +#include <stdio.h> +#define printd(...) \ + do { \ + fprintf(stderr, "%lu ", pthread_self()); \ + fprintf(stderr, "%s(): ", __FUNCTION__ ); \ + fprintf(stderr, __VA_ARGS__); \ + fflush(stderr); \ + } while(0) + +void printfl(filock_t *fl) +{ + struct locked_range *lr; + struct waiter_range *wr; + + fprintf(stderr, "Filock show\n"); + + fprintf(stderr, "Locked:\n"); + for (lr = fl->locked; lr != NULL; lr = lr->next) { + fprintf(stderr, "\t%lu -> %lu (%u) (%lu)\n", lr->start, + lr->end, lr->mode, lr->owner); + } + + fprintf(stderr, "Waiter:\n"); + for (wr = fl->waiters; wr != NULL; wr = wr->next) { + fprintf(stderr, "\t%lu -> %lu (%u) (%lu)\n", wr->start, + wr->end, wr->mode, wr->owner); + } +} +#else + #define printd(...) + #define printfl(X) +#endif + +/* Lock/unlock a filock_t */ +#define fl_lock(F) do { pthread_mutex_lock(&(F->lock)); } while (0) +#define fl_unlock(F) do { pthread_mutex_unlock(&(F->lock)); } while (0) + + +/* Initialize a filock_t structure */ +int filo_init(filock_t *fl) +{ + pthread_mutexattr_t attr; + pthread_mutexattr_init(&attr); + pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_NORMAL); + pthread_mutex_init(&(fl->lock), &attr); + pthread_mutexattr_destroy(&attr); + + fl->locked = NULL; + fl->waiters = NULL; + return 1; +} + +/* Frees a filock_t structure */ +int filo_free(filock_t *fl) +{ + struct locked_range *lr, *nlr; + struct waiter_range *wr, *nwr; + + pthread_mutex_destroy(&(fl->lock)); + + for (lr = fl->locked; lr != NULL; lr = nlr) { + nlr = lr->next; + free(lr); + } + fl->locked = NULL; + + for (wr = fl->waiters; wr != NULL; wr = nwr) { + nwr = wr->next; + free(wr); + } + fl->waiters = NULL; + + return 1; +} + +/* Appends a lock to the filock_t */ +static void locked_append(filock_t *fl, off_t start, off_t end, int mode, + pthread_t owner) +{ + struct locked_range *lr; + + lr = malloc(sizeof(struct locked_range)); + lr->start = start; + lr->end = end; + lr->mode = mode; + lr->owner = owner; + + if (fl->locked == NULL) { + lr->prev = lr->next = NULL; + fl->locked = lr; + printd("n: %lu-%lu %d %lu\n", start, end, mode, owner); + } else { + lr->prev = NULL; + fl->locked->prev = lr; + lr->next = fl->locked; + fl->locked = lr; + printd("e: %lu-%lu %d %lu\n", start, end, mode, owner); + } +} + +/* Checks if this thread owns the given locked range */ +static int is_ours(struct locked_range *lr) +{ + return !!pthread_equal(lr->owner, pthread_self()); +} + +/* Checks the given thread owns the given locked range */ +static int is_owner(pthread_t owner, struct locked_range *lr) +{ + return !!pthread_equal(lr->owner, owner); +} + + +/* Checks if the range 1 overlaps with the range 2 */ +static int range_overlaps(off_t start1, off_t end1, off_t start2, off_t end2) +{ + if ( (start1 <= start2 && end1 >= end2) || + (start1 >= start2 && start1 <= end2) || + (end1 >= start2 && end1 <= end2) ) { + return 1; + } + return 0; +} + +/* Range overlapping check for locked ranges */ +static int lr_range_overlaps(struct locked_range *lr, off_t start, off_t end) +{ + printd("%lu->%lu ov %lu->%lu: %d\n", lr->start, lr->end, start, end, range_overlaps(lr->start, lr->end, start, end)); + return range_overlaps(lr->start, lr->end, start, end); +} + +/* Range overlapping check for waiter ranges */ +static int wr_range_overlaps(struct waiter_range *wr, off_t start, off_t end) +{ + return range_overlaps(wr->start, wr->end, start, end); +} + + +/* So far we know: + * * there's overlapping between lr and start-end + * * we own lr + * We need to solve the problem by doing: + * * If lr is inside start-end, remove it + * * If start-end is inside lr, do an "exclude" and break lr in two + * * If there's partial overlapping, shrink lr not to step on start-end + */ +static int exclude_range(filock_t *fl, struct locked_range *lr, + off_t start, off_t end) +{ + printd("exclude %lu->%lu from %lu->%lu\n", start, end, lr->start, lr->end); + if (lr->start >= start && lr->end <= end) { + /* it's equal or contained inside, tell to remove */ + return 0; + } else if (lr->start < start && lr->end <= end) { + /* we're overlapping from the left, shrink it */ + printd("shrink end from %lu to %lu\n", lr->end, start - 1); + lr->end = start - 1; + return 1; + } else if (lr->start >= start && lr->end > end) { + /* we're overlapping from the right, shrink it */ + printd("shrink start %lu to %lu\n", lr->start, end + 1); + lr->start = end + 1; + return 1; + } else if (lr->start < start && lr->end > end) { + /* start-end is contained inside lr, we need to split lr */ + locked_append(fl, lr->start, start - 1, lr->mode, + pthread_self()); + locked_append(fl, end + 1, lr->end, lr->mode, pthread_self()); + /* tell the caller to remove lr */ + return 0; + } + + /* we should NEVER enter here, since all the cases should have been + * covered */ + return 1; +} + + +/* Checks if the given thread can lock the given region */ +static int can_lock_tid(filock_t *fl, off_t start, off_t end, int mode, + pthread_t owner) +{ + struct locked_range *lr; + + for (lr = fl->locked; lr != NULL; lr = lr->next) { + /* if we are inside, contained or overlapping somebody else, + * check if: + * * is ours, so we can play with it freely + * * is a write lock and we try to read, can't get it + * * we try to write, can't get it + */ + if (lr_range_overlaps(lr, start, end)) { + if (is_owner(owner, lr)) { + /* this check could be moved before the long + * "if" above, but it's an unlikely case and + * the test could get expensive */ + continue; + } + if (mode == FL_WR_MODE || lr->mode == FL_WR_MODE) { + return 0; + } + } + } + printd("can lock it from %lu to %lu as %d\n", start, end, mode); + return 1; +} + +/* As can_lock_tid() but gets the owner from the current thread */ +static int can_lock(filock_t *fl, off_t start, off_t end, int mode) +{ + return can_lock_tid(fl, start, end, mode, pthread_self()); +} + + +/* Lock a given region, assuming that is not free and we're allowed to own it + * (these checks are performed by the caller) */ +static int do_lock_tid(filock_t *fl, off_t start, off_t end, int mode, + pthread_t owner) +{ + struct locked_range *lr, *next; + + for (lr = fl->locked; lr != NULL; lr = next) { + next = lr->next; + + if (!is_ours(lr)) + continue; + if (!lr_range_overlaps(lr, start, end)) + continue; + + printd("overlap %lu %lu %d %lu\n", start, end, mode, owner); + if (exclude_range(fl, lr, start, end) == 0) { + printd("rem lr %lu->%lu\n", lr->start, lr->end); + /* we need to remove lr */ + if (fl->locked == lr) + fl->locked = lr->next; + if (lr->prev != NULL) + lr->prev->next = lr->next; + if (lr->next != NULL) + lr->next->prev = lr->prev; + free(lr); + } + } + + /* now the region is safe to do this */ + locked_append(fl, start, end, mode, owner); + return 1; +} + + +/* Same as do_lock_tid(), but gets the tid from the currently running thread; + * it's a shortcut for a lot of uses */ +static int do_lock(filock_t *fl, off_t start, off_t end, int mode) +{ + return do_lock_tid(fl, start, end, mode, pthread_self()); +} + + +/* Check if a region is free from locks so we can add the lock right in, + * skipping all the other tests */ +static int region_free(filock_t *fl, off_t start, off_t end) { + struct locked_range *lr; + for (lr = fl->locked; lr != NULL; lr = lr->next) { + if (lr_range_overlaps(lr, start, end)) + return 0; + } + return 1; +} + +/* Tries to get a lock, returns 1 if success or 0 if failure */ +int filo_trylock(filock_t *fl, off_t start, off_t len, int mode) +{ + int rv = 0; + int end = start + len; + + fl_lock(fl); + + /* fast path for the uncontended case */ + if (fl->locked == NULL) { + locked_append(fl, start, end, mode, pthread_self()); + rv = 1; + } else if (region_free(fl, start, end)) { + locked_append(fl, start, end, mode, pthread_self()); + rv = 1; + } else if (can_lock(fl, start, end, mode)) { + do_lock(fl, start, end, mode); + rv = 1; + } else { + /* the region is busy, we would lock */ + rv = 0; + } + + fl_unlock(fl); + return rv; +} + + +static void wait_on(filock_t *fl, off_t start, off_t end, int mode) +{ + /* all waiter_ranges live on the heap and are created and destroyed + * here. A wr is born here, go to bed in the locking below, until + * wake_up() wakes us up and he dies. While it is manipulated several + * times outside this function, here is the only place where it's + * actually modified. */ + struct waiter_range wr; + + /* initialize wr */ + wr.start = start; + wr.end = end; + wr.mode = mode; + wr.owner = pthread_self(); + wr.next = NULL; + wr.prev = NULL; + + sem_init(&(wr.sem), 0, 0); + + /* add to the list */ + if (fl->waiters == NULL) { + wr.next = wr.prev = NULL; + fl->waiters = ≀ + } else { + wr.prev = NULL; + fl->waiters->prev = ≀ + wr.next = fl->waiters; + fl->waiters = ≀ + } + + fl_unlock(fl); + + /* block until some other thread wakes us up */ + sem_wait(&(wr.sem)); +} + +static void wake_up(filock_t *fl, off_t start, off_t end) +{ + struct waiter_range *wr; + + for (wr = fl->waiters; wr != NULL; wr = wr->next) { + if (!wr_range_overlaps(wr, start, end)) + /* if the region doesn't overlap, we know beforehand + * the status couldn't have changed */ + continue; + if (can_lock_tid(fl, wr->start, wr->end, wr->mode, wr->owner)) { + do_lock_tid(fl, wr->start, wr->end, wr->mode, + wr->owner); + + /* remove from the list */ + if (fl->waiters == wr) + fl->waiters = wr->next; + if (wr->prev != NULL) + wr->prev->next = wr->next; + if (wr->next != NULL) + wr->next->prev = wr->prev; + /* it lives on wait_on()'s stack, there's no need to + * free it */ + + /* this will wake the thread up (and the thread will + * destroy wr) */ + sem_post(&(wr->sem)); + + return; + } + } + + /* nobody was waiting! */ + return; +} + + +/* Get a lock, blocking until available */ +int filo_lock(filock_t *fl, off_t start, off_t len, int mode) +{ + off_t end = start + len; + + fl_lock(fl); + + /* fast path for the uncontended case */ + if (fl->locked == NULL) { + locked_append(fl, start, end, mode, pthread_self()); + fl_unlock(fl); + } else if (region_free(fl, start, end)) { + locked_append(fl, start, end, mode, pthread_self()); + fl_unlock(fl); + } else if (can_lock(fl, start, end, mode)) { + printd("locking\n"); + do_lock(fl, start, end, mode); + fl_unlock(fl); + } else { + /* the region is busy, we wait */ + wait_on(fl, start, end, mode); + /* when we return, fl->lock has already been unlocked, there's + * no need to release it */ + } + + printfl(fl); + return 1; +} + + +int filo_unlock(filock_t *fl, off_t start, off_t len) +{ + struct locked_range *lr, *next; + off_t end = start + len; + + fl_lock(fl); + + for (lr = fl->locked; lr != NULL; lr = next) { + next = lr->next; + + if (!is_ours(lr)) + continue; + if (!lr_range_overlaps(lr, start, end)) + continue; + + /* the range is ours and overlaps, unlock this area */ + if (exclude_range(fl, lr, start, end) == 0) { + /* we need to remove lr */ + if (fl->locked == lr) + fl->locked = lr->next; + if (lr->prev != NULL) + lr->prev->next = lr->next; + if (lr->next != NULL) + lr->next->prev = lr->prev; + free(lr); + } + } + + wake_up(fl, start, end); + printd("UNLOCKED\n"); + printfl(fl); + fl_unlock(fl); + return 1; +} + + diff --git a/libfilo.h b/libfilo.h new file mode 100644 index 0000000..6e65fbb --- /dev/null +++ b/libfilo.h @@ -0,0 +1,60 @@ + +/* + * libfilo - A File Locking Library + * Alberto Bertogli (albertogli@telpin.com.ar) + */ + + +#ifndef _LIBFILO_H +#define _LIBFILO_H + +#include <pthread.h> +#include <semaphore.h> +#include <unistd.h> /* because filo_plockf() uses the same constants as + * lockf() */ + + +/* locking modes */ +#define FL_RD_MODE 0 +#define FL_WR_MODE 1 + + +/* a single locked range */ +struct locked_range { + off_t start; + off_t end; + int mode; + pthread_t owner; + struct locked_range *next; + struct locked_range *prev; +}; + +/* a range waiting for read or write */ +struct waiter_range { + off_t start; + off_t end; + int mode; + pthread_t owner; + sem_t sem; + struct waiter_range *next; + struct waiter_range *prev; +}; + +/* a file lock */ +typedef struct filo_flock_t { + struct locked_range *locked; + struct waiter_range *waiters; + pthread_mutex_t lock; +} filock_t; + + +int filo_init(filock_t *fl); +int filo_free(filock_t *fl); +int filo_lock(filock_t *fl, off_t start, off_t len, int mode); +int filo_trylock(filock_t *fl, off_t start, off_t len, int mode); +int filo_unlock(filock_t *fl, off_t start, off_t len); +int filo_islocked(filock_t *fl, off_t start, off_t len); +int filo_plockf(filock_t *fl, int cmd, off_t start, off_t len); + +#endif +