Giter Club home page Giter Club logo

Comments (11)

xaionaro avatar xaionaro commented on July 19, 2024

How to repeat the bug on FreeBSD:

mkdir -p /tmp/test/1

cat > /tmp/main.c << EOF
#include <sys/inotify.h>

int main() {
        int inotify_d = inotify_init();
        inotify_add_watch(inotify_d, "/tmp/test", 0x2000fce);
        return inotify_add_watch(inotify_d, "/tmp/test/1", 0x2000fce);
}
EOF
gcc49 -linotify /tmp/main.c -o /tmp/test.bin
/tmp/test.bin

from libinotify-kqueue.

xaionaro avatar xaionaro commented on July 19, 2024

It's just a race conditions. There's no bug if I insert sleep(3) between inotify_add_watch() calls in the example above.

from libinotify-kqueue.

dmatveev avatar dmatveev commented on July 19, 2024

Thanks for report. Looks like that busy wait is really busy. Do tests run ok on your system? (make test).

In any case, could you please comment out line 16 in barriers.h (#define WITHOUT_BARRIERS), rebuild the library and try to reproduce it again?

from libinotify-kqueue.

xaionaro avatar xaionaro commented on July 19, 2024

make test (for recent git version of libinotify):

[root@freebsd10 /tmp/libinotify-kqueue]# make test
Running test suite...
..............xx.......xx.....x....xx...xx...xx.x.............

In test "Start-stop test":
    failed: all produced events are registered after resume

In test "Start-stop directory":
    failed: receive all events on a resumed watch
    failed: receive events for a same file from both watches (sometimes this test fails event on Linux, at least on 2.6.39)

In test "Update watch flags":
    failed: receive notifications on modify with flags = IN_ATTRIB | IN_MODIFY
    failed: do not receive notifications on touch with flags = IN_MODIFY 

In test "Update directory flags":
    failed: receive modify notifications for files in a directory with IN_MODIFY

In test "Open/close notifications":
    failed: receive IN_OPEN on cat
    failed: receive IN_CLOSE_NOWRITE on cat
    failed: receive IN_OPEN on ls
    failed: receive IN_CLOSE_NOWRITE on ls
    failed: receive IN_OPEN on modify
    failed: receive IN_CLOSE_WRITE on modify

--------------------
     Run: 62
  Passed: 50
  Failed: 12

make test (from ports):

[root@freebsd10 /usr/ports/devel/libinotify/work/dmatveev-libinotify-kqueue-2a0d601]# make test
gcc49 -O2 -pipe  -I/usr/ports/devel/libinotify/work/dmatveev-libinotify-kqueue-2a0d601 -DNDEBUG -pthread -std=gnu99 -fstack-protector  -linotify -L/usr/local/lib test.c  -o test
[root@freebsd10 /usr/ports/devel/libinotify/work/dmatveev-libinotify-kqueue-2a0d601]# make test
`test' is up to date.
[root@freebsd10 /usr/ports/devel/libinotify/work/dmatveev-libinotify-kqueue-2a0d601]# ./test
Watching the current directory

In any case, could you please comment out line 16 in barriers.h (#define WITHOUT_BARRIERS), rebuild the library and try to reproduce it again?

Works :)

[root@freebsd10 /usr/ports/devel/libinotify/work/dmatveev-libinotify-kqueue-2a0d601]# time /tmp/test.bin

real    0m0.003s
user    0m0.000s
sys     0m0.008s

from libinotify-kqueue.

xaionaro avatar xaionaro commented on July 19, 2024

Tests are made on separate virtual machine, so I can share it with you if you wish)

from libinotify-kqueue.

xaionaro avatar xaionaro commented on July 19, 2024

The race condition appears due to next problem:

OS saves CPU using rare context switching, so there may be no context switch between "--impl->sleeping" and "++impl->sleeping". And that's how the deadlock appears with infinite "while (impl->sleeping != 0);" and "pthread_cond_wait()".

It's required to allow the loop ("while (impl->sleeping != 0)") to end despite this. I think I can prepare a patch.

Sorry for my English. I hope I make myself clear.

from libinotify-kqueue.

xaionaro avatar xaionaro commented on July 19, 2024

The patch is ready.

from libinotify-kqueue.

dmatveev avatar dmatveev commented on July 19, 2024

Confirmed on NetBSD

from libinotify-kqueue.

dmatveev avatar dmatveev commented on July 19, 2024

The issue was in the ik_barrier_impl_wait function. In our scenario, we had two threads -- a main thread and a kqueue worker thread. Barriers are used to synchronize both threads when passing commands (add watch, rm watch) from main to worker.

Main                             Worker
----                             ------
inotify_add_watch()              kevent()
  worker_cmd_add()                :
  write(fd, "*")      ---------> kevent() returns
  worker_cmd_wait()                process_command()
    ik_barrier_wait()                worker_cmd_wait()
    [1]                                ik_barrier_wait()
                                       [2]

At [1], the main thread serializes the command data in a special structure, sends a notification to the worker thread, and blocks on a barrier. The worker thread wakes up, processes the command, passes back result, and also checks in on a barrier [2].

Having a busy wait to ensure all threads release barrier's locks was a bad idea. In our scenario, the main thread left the barrier, then destroyed it, and then initialized with new data again (in the subsequent call to inotify_add_watch()) BEFORE the worker thread started to busy wait on the barrier.

In other words (c is the counter):

Thread A     Thread B
--------     --------
Enter(c=0)       :
  Sleep        Enter(c=1)
  Wake up <--    Signal
Leave            :   
Destroy          :
Init(c=0)        :
Enter(c=1)       :
                 Busy wait(c=1)

from libinotify-kqueue.

xaionaro avatar xaionaro commented on July 19, 2024

I'll test the new version for my case tomorrow :)

from libinotify-kqueue.

xaionaro avatar xaionaro commented on July 19, 2024

Thanks. The new version doesn't hang. :)

from libinotify-kqueue.

Related Issues (18)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.