File locking on Solaris - Unix

This is a discussion on File locking on Solaris - Unix ; I'm in progress of implementing a process-wide filelocking to avoid mutual executions when saving data to a shared data area. The problem is when you have a process which is executed multiple times and this reads and writes multiple files. ...

+ Reply to Thread
Results 1 to 17 of 17

Thread: File locking on Solaris

  1. File locking on Solaris

    I'm in progress of implementing a process-wide filelocking to avoid mutual
    executions when saving data to a shared data area.

    The problem is when you have a process which is executed multiple times and
    this reads and writes multiple files. During this time I want to avoid
    inconsistency. Therefore I'm creating a temporary lock file is needs to be
    locked.
    This lockfile is opened by fopen.

    In linux and Windows I solve it in the following way:

    if (flock(fileno(m_fp), LOCK_EX) != 0)
    return false;

    while (_locking(_fileno(m_fp), _LK_NBLCK, filelen(m_fp) + 1000000) != 0)
    {
    if (errno == EACCES || errno == EDEADLOCK)
    {
    Sleep(5);
    continue;
    }

    return false;
    }


    However the linux method doesn't work with Solaris. Even though Solaris
    claims to have the flock api implemented it's missing the LOCK_EX macro
    which is not present in sys/file.h

    Therefore I am asking for an alternative method for acomplishing the same
    task.

    Thanks.

    -- Henrik



  2. Re: File locking on Solaris

    On Jan 11, 2:31 pm, "Henrik Goldman"
    wrote:
    > I'm in progress of implementing a process-wide filelocking to avoid mutual
    > executions when saving data to a shared data area.
    > The problem is when you have a process which is executed multiple times and
    > this reads and writes multiple files. During this time I want to avoid
    > inconsistency. Therefore I'm creating a temporary lock file is needs to be
    > locked.
    > This lockfile is opened by fopen.
    > In linux and Windows I solve it in the following way:
    > if (flock(fileno(m_fp), LOCK_EX) != 0)
    > return false;
    > while (_locking(_fileno(m_fp), _LK_NBLCK, filelen(m_fp) + 1000000) != 0)
    > {
    > if (errno == EACCES || errno == EDEADLOCK)
    > {
    > Sleep(5);
    > continue;
    > }
    > return false;
    > }
    > However the linux method doesn't work with Solaris. Even though Solaris
    > claims to have the flock api implemented it's missing the LOCK_EX macro
    > which is not present in sys/file.h

    I think it is...
    > Therefore I am asking for an alternative method for acomplishing the same task.


    What part of man flock did you miss??
    The "macro" lives in /usr/ucbinclude.
    flock is a BSD compatability thing, I think the gist of the man page
    is to
    use fcntl instead.

  3. Re: File locking on Solaris

    In comp.unix.programmer Henrik Goldman wrote:
    > Therefore I am asking for an alternative method for acomplishing the same
    > task.


    Try something like this:

    struct flock fl;
    int result;

    memset(&fl, 0, sizeof fl);

    fl.l_type = F_WRLCK;
    fl.l_whence = SEEK_SET;
    fl.l_start = 0;
    fl.l_len = 0;
    fl.l_pid = getpid();

    result = fcntl(fd, F_SETLKW, &fl);
    if (result != -1)
    /* success */
    else
    /* failure */

  4. Re: File locking on Solaris

    On Fri, 11 Jan 2008, Henrik Goldman wrote:

    > The problem is when you have a process which is executed multiple times and
    > this reads and writes multiple files. During this time I want to avoid
    > inconsistency. Therefore I'm creating a temporary lock file is needs to be
    > locked.
    > This lockfile is opened by fopen.
    >
    > In linux and Windows I solve it in the following way:
    >
    > if (flock(fileno(m_fp), LOCK_EX) != 0)
    > return false;


    flock is a holdover from the BSD days, and isn't recommended for Solaris.
    I strongly recommend you use lockf() instead.

    --
    Rich Teer, SCSA, SCNA, SCSECA, OGB member

    CEO,
    My Online Home Inventory

    URLs: http://www.rite-group.com/rich
    http://www.linkedin.com/in/richteer
    http://www.myonlinehomeinventory.com

  5. Re: File locking on Solaris

    "Henrik Goldman" writes:

    >However the linux method doesn't work with Solaris. Even though Solaris
    >claims to have the flock api implemented it's missing the LOCK_EX macro
    >which is not present in sys/file.h


    It doesn't have the flock() function; only in the BSD compatibility
    library; Solaris supports fcntl() style locking only.

    Casper
    --
    Expressed in this posting are my opinions. They are in no way related
    to opinions held by my employer, Sun Microsystems.
    Statements on Sun products included here are not gospel and may
    be fiction rather than truth.

  6. Re: File locking on Solaris

    Hi Rich,

    > flock is a holdover from the BSD days, and isn't recommended for Solaris.
    > I strongly recommend you use lockf() instead.


    Unfortunately it won't work with fopen filedescriptors. The man page says
    it's incompatible with this.
    This code is part of a core library and changing the dependencies is
    unfortunately not an option unless I write new wrappers for fread, fwrite,
    fprintf and fscanf as well.

    -- Henrik



  7. Re: File locking on Solaris

    Hi Ed,

    > Try something like this:
    >

    ....
    > fl.l_pid = getpid();
    >
    > result = fcntl(fd, F_SETLKW, &fl);


    Thanks. I tried this but I see that it also depends on the PID. The solution
    I was hoping for was so have something that blocks on all threads.
    Therefore my tests are still failing with this. The linux solution provided
    works as expected but unfortunately not under Solaris.

    Do you know if it's compatible with file descriptors opened with fopen?
    The man page doesn't mention anything on this.

    -- Henrik




  8. Re: File locking on Solaris

    Henrik Goldman wrote:
    > Hi Ed,
    >
    >> Try something like this:
    >>

    > ...
    >> fl.l_pid = getpid();
    >>
    >> result = fcntl(fd, F_SETLKW, &fl);

    >
    > Thanks. I tried this but I see that it also depends on the PID. The solution
    > I was hoping for was so have something that blocks on all threads.
    > Therefore my tests are still failing with this. The linux solution provided
    > works as expected but unfortunately not under Solaris.
    >
    > Do you know if it's compatible with file descriptors opened with fopen?
    > The man page doesn't mention anything on this.
    >

    UNIX locking is based on processes. IOW, you cannot lock a file against
    yourself.

    This has nothing to do with whether the file is being handled using FILE
    * or an int fd.

    Using threads on a UNIX means that you cannot lock against another
    thread, Linux implementations of threads cause a new "execution object"
    to be created, which is a different /process/, so, you *can* lock
    against yourself (because you *aren't* locking against yourself). (Hmm,
    this may not be true for NPTL, I haven't looked into it.)

    Why do you need to allow threads to lock files against each other? Are
    there other processes that may be accessing the files? IOW - what's
    wrong with using mutexes?

    Cheers,
    Gary B-)

    --
    __________________________________________________ ____________________________
    Armful of chairs: Something some people would not know
    whether you were up them with or not
    - Barry Humphries

  9. Re: File locking on Solaris

    Hi Gary,

    > Using threads on a UNIX means that you cannot lock against another thread,
    > Linux implementations of threads cause a new "execution object" to be
    > created, which is a different /process/, so, you *can* lock against
    > yourself (because you *aren't* locking against yourself). (Hmm, this may
    > not be true for NPTL, I haven't looked into it.)


    From my tests even for NPTL the file locks are working as they should on
    both thread and process level.

    > Why do you need to allow threads to lock files against each other?


    The code I'm making is sort of a database layer that can spawn over multiple
    files.
    Assume you have a set of data that can spawn over 10 files. If you have 2
    processes writing to these files at the same time then corruption can
    happen.
    Thats what I want to avoid by putting a process and thread wide lock on the
    system to prevent multiple access.

    > Are there other processes that may be accessing the files?


    Yes there can be multiple threads and processes accessing this layer. Please
    keep in mind that it's more than just 1 file being affected by these
    processes.

    > IOW - what's wrong with using mutexes?


    Absolutely nothing except that it won't work when spawning multiple
    instances of the same application.
    Based on experience this is what has caused our application these weird
    "ups... why it fail every 200 time" errors.

    Here is the testcase I'm writing. I'm sorry for not posting the entire code
    but most of the sorrounding code is rather irrelevant to this problem.
    Fixing the problem with a mutex is easy ... but then I would like to get
    guidance on how to improve the actual test with e.g. fork().

    What I'm doing in this test is to spawn a number of threads using
    pthread_create which each open up a smartpointer file that implements RAII
    idiom for fclose when the object goes out of scope.
    Furthermore I open up a lockfile called testfp_lock.txt which is assumed to
    be a process wide lock.
    Then I open up another file where I write a random number which is then read
    back again.

    The fp.Lock() is what holds this locking mechanism.
    Assuming that I would implement a mutex in Lock() it would make the testcase
    work obviously since all threads would wait until it's their turn.
    However perhaps someone can recommend on how to improve this test to
    additionally use fork to ensure it also holds for process-wide locking e.g.
    to ensure that methods like fcntl indeed work as expected?

    Thanks.
    -- Henrik

    ----------------
    struct FileCountThreadFixture

    {

    virtual ~FileCountThreadFixture() {}

    static void Callback(CThreadInformation *pParam)

    {

    int i;

    CSmartFILEPtr fp, fp2;

    int n1, n2;

    CPrng prng;

    THREAD_CHECK(prng.SeedFromSystem());

    THREAD_CHECK((fp = fopen("testfp_lock.txt", "w")) != NULL);

    THREAD_CHECK(fp.Lock());

    for (i = 0; i < 10; i++)

    {

    n1 = (int) prng.Rand32();

    THREAD_CHECK((fp2 = fopen("testfp.txt", "w")) != NULL);

    fprintf(fp2, "%d", n1);

    fp2.Close();

    THREAD_CHECK((fp2 = fopen("testfp.txt", "r")) != NULL);

    THREAD_CHECK(fscanf(fp2, "%d", &n2) == 1);

    fp2.Close();

    THREAD_CHECK(n1 == n2);

    }

    *(bool *) pParam->m_pParam = true;

    }

    };

    TEST_FIXTURE(FileCountThreadFixture, LockTest_FP)

    {

    CThread t[10];

    bool bFinished[10];

    int i;

    for (i = 0; i < lengthof(t); i++)

    {

    bFinished[i] = false;

    t[i].SetCallback(Callback);

    t[i].SetParam(&bFinished[i]);

    CHECK(t[i].Start());

    }

    for (i = 0; i < lengthof(t); i++)

    {

    t[i].Join();

    CHECK(bFinished[i]);

    }

    CHECK(remove("testfp.txt") == 0);

    CHECK(remove("testfp_lock.txt") == 0);

    }



  10. Re: File locking on Solaris

    "Henrik Goldman" writes:

    >Hi Rich,


    >> flock is a holdover from the BSD days, and isn't recommended for Solaris.
    >> I strongly recommend you use lockf() instead.


    >Unfortunately it won't work with fopen filedescriptors. The man page says
    >it's incompatible with this.


    That's not what the manual page says: it says that locking and stdio
    don't go together in a meaningful way because of buffering; if all you
    want is a "lock" and don't do I/O then that's fine.

    Casper
    --
    Expressed in this posting are my opinions. They are in no way related
    to opinions held by my employer, Sun Microsystems.
    Statements on Sun products included here are not gospel and may
    be fiction rather than truth.

  11. Re: File locking on Solaris

    "Henrik Goldman" writes:

    >Hi Ed,


    >> Try something like this:
    >>

    >...
    >> fl.l_pid = getpid();
    >>
    >> result = fcntl(fd, F_SETLKW, &fl);


    >Thanks. I tried this but I see that it also depends on the PID. The solution
    >I was hoping for was so have something that blocks on all threads.


    That does not exist; it's the process which holds the locks.

    >Therefore my tests are still failing with this. The linux solution provided
    >works as expected but unfortunately not under Solaris.


    Then it's not POSIX compliant locking. Are you sure it works with NPTL
    threads also (Linux Threads are a form of processes and as such behave
    "process like" in some context; but with NPTL becoming the norm, that
    behaviour will go away as it is an implementation artefact)

    >Do you know if it's compatible with file descriptors opened with fopen?
    >The man page doesn't mention anything on this.


    All plain file file descriptors work the same, regardless of whether they
    have been opened with fopen() or open().

    The warning in the manual page is about things like:


    lock(fileno(fp))
    fwrite(fp)
    unlock(fileno(fp))

    which does not do what you want because no data may be written by
    fwrite.

    Casper
    --
    Expressed in this posting are my opinions. They are in no way related
    to opinions held by my employer, Sun Microsystems.
    Statements on Sun products included here are not gospel and may
    be fiction rather than truth.

  12. Re: File locking on Solaris

    "Henrik Goldman" writes:

    >From my tests even for NPTL the file locks are working as they should on
    >both thread and process level.


    If they work "per thread" then they are NOT working as they should;
    the locks are per-process and they MUST work between processes, not
    threads.

    >The code I'm making is sort of a database layer that can spawn over multiple
    >files.
    >Assume you have a set of data that can spawn over 10 files. If you have 2
    >processes writing to these files at the same time then corruption can
    >happen.
    >Thats what I want to avoid by putting a process and thread wide lock on the
    >system to prevent multiple access.


    On the whole database or the an individual file?

    Casper
    --
    Expressed in this posting are my opinions. They are in no way related
    to opinions held by my employer, Sun Microsystems.
    Statements on Sun products included here are not gospel and may
    be fiction rather than truth.

  13. Re: File locking on Solaris

    "Henrik Goldman" writes:
    >> flock is a holdover from the BSD days, and isn't recommended for Solaris.
    >> I strongly recommend you use lockf() instead.

    >
    > Unfortunately it won't work with fopen filedescriptors. The man page says
    > it's incompatible with this.


    There is no such thing as 'a fopen filedescriptor' and the man page
    states that, for actual 'record' (byterange) locking to work, actual
    I/O must by sychronized with the locking calls, instead of (which is
    an example) just stored into a stdio-buffer to be written at an
    unspecified later date.

  14. Re: File locking on Solaris

    Ed Jensen writes:
    > struct flock fl;
    > int result;
    >
    > memset(&fl, 0, sizeof fl);
    >
    > fl.l_type = F_WRLCK;
    > fl.l_whence = SEEK_SET;
    > fl.l_start = 0;
    > fl.l_len = 0;
    > fl.l_pid = getpid();
    >
    > result = fcntl(fd, F_SETLKW, &fl);
    > if (result != -1)


    The fl.l_pid member is only used to return the pid of a process
    holding a lock when using the F_GETLK request.

  15. Re: File locking on Solaris

    "Gary R. Schmidt" writes:

    [...]

    > Linux implementations of threads cause a new "execution
    > object" to be created, which is a different /process/,


    It is not. A process is a set of ressources, one of them being a
    virtual address space of itst own, shared among one or more threads of
    execution. Linux is not UNIX(*) and it never had the (traditional)
    UNIX(*)-implementation of 'a process', either. The kernel schedules
    'tasks' (things represented by a struct task_struct) and these tasks
    access resources (like an address space or a file descriptor table)
    through pointers, and sharing any or all of these ressources with other
    tasks is possible. A 'traditional' process is then implemented by a
    task not sharing anything with anyone, and 'some kind of thread' would
    be a task sharing an address space with some other tasks (and
    potentially other ressources, too).

  16. Re: File locking on Solaris

    Casper H.S. Dik writes:

    [...]

    > (Linux Threads are a form of processes


    The LinuxThreads implementation of POSIX thread support is not
    completely compatible with the pthread specification because of
    lacking kernel support at the time it was written. For instance, the
    'Linux native way' to create a new thread of execution within some
    given address space originally didn't support the POSIX signal
    handling model with 'per thread' and 'per process' signals, but only
    the former. Going along with this, it didn't support 'process IDs'
    either, only 'thread ids'. It would actually be technically more
    accurate to state that pre-2.6-Linux didn't support processes and that
    Linux 'processes' where just a form of threads.

    To continue the fine tradition of ignoring the actual properties of an
    implementation in favor of being able to (badly) fit terms coined for
    other implementations to it, people have meanwhile begun to talk about
    'Linux LWPs' because Linux processes are now implemented as 'thread
    groups' with both an ID and signal reception capabilities of its own.

  17. Re: File locking on Solaris


    >>Assume you have a set of data that can spawn over 10 files. If you have 2
    >>processes writing to these files at the same time then corruption can
    >>happen.
    >>Thats what I want to avoid by putting a process and thread wide lock on
    >>the
    >>system to prevent multiple access.

    >
    > On the whole database or the an individual file?
    >


    On the whole database.

    -- Henrik



+ Reply to Thread