vibe-d / vibe.d

Official vibe.d development
MIT License
1.15k stars 284 forks source link

Directory Watcher. Leaked handles detected at driver shutdown #2486

Open FreeSlave opened 3 years ago

FreeSlave commented 3 years ago

Running this application with vibe-d 0.9.2

import core.time;
import vibe.core.file;
import vibe.core.log;
import vibe.core.task;
import vibe.core.core;

void main()
{
    runTask({
        auto watcher = watchDirectory("./test", false);
        while(true)
        {
            DirectoryChange[] changes;
            if (watcher.readChanges(changes, dur!"seconds"(-1)))
            {
                foreach(ref change; changes)
                {
                    logInfo("Changed file: %s\n", change);
                }
            }
        }
    });
    runApplication();
}

When I press Ctrl+C on Windows (did not try on other systems yet) it reports:

Warning (thread: main): Leaked handles detected at driver shutdown
   FD 0204 (watcher)

I'm not sure though if I'm doing it right. I think there should be a directory watcher example in 'examples/' directory of the repository.

FreeSlave commented 3 years ago

I checked and similar thing happens on Linux.

Warning (thread: main): leaking eventcore driver because there are still active handles
   FD 6 (watcher)

Warning (thread: main): leaking eventcore driver because there are still active handles
   FD 6 (watcher)

I tried it with VibeHighEventPriority enabled but without any success.

Geod24 commented 3 years ago

@FreeSlave : I can't reproduce on OSX. Do you still see it with the latest release ?

FreeSlave commented 3 years ago

@Geod24 I've just tried it on Linux with vibecore 1.18.0

Warning (thread: main): leaking eventcore driver because there are still active handles
  FD 6 (watcher)
Created by;
      ../../.dub/packages/vibe-core-1.18.0/vibe-core/source/vibe/core/file.d:543 @safe vibe.core.file.DirectoryWatcher vibe.core.file.watchDirectory(vibe.core.path.GenericPath!(vibe.core.path.PosixPathFormat).GenericPath, bool) [0x5640ed43772b]
      ../../.dub/packages/vibe-core-1.18.0/vibe-core/source/vibe/core/file.d:548 @safe vibe.core.file.DirectoryWatcher vibe.core.file.watchDirectory(immutable(char)[], bool) [0x5640ed3f7755]
      source/app.d:10 @safe void app.main().__lambda1() [0x5640ed3ebdf9]
      ../../.dub/packages/vibe-core-1.18.0/vibe-core/source/vibe/core/task.d:718 void vibe.core.task.TaskFuncInfo.set!(void function() @safe*).set(ref void function() @safe*).callDelegate(ref vibe.core.task.TaskFuncInfo) [0x5640ed3f072a]
      ../../.dub/packages/vibe-core-1.18.0/vibe-core/source/vibe/core/task.d:739 void vibe.core.task.TaskFuncInfo.call() [0x5640ed40efc5]
      ../../.dub/packages/vibe-core-1.18.0/vibe-core/source/vibe/core/task.d:446 nothrow void vibe.core.task.TaskFiber.run() [0x5640ed40e28b]
      ??:? void core.thread.context.Callable.opCall() [0x5640ed4a6088]
      ??:? fiber_entryPoint [0x5640ed4dbe7b]
Warning (thread: main): leaking eventcore driver because there are still active handles
  FD 6 (watcher)
    Created by;
      ../../.dub/packages/vibe-core-1.18.0/vibe-core/source/vibe/core/file.d:543 @safe vibe.core.file.DirectoryWatcher vibe.core.file.watchDirectory(vibe.core.path.GenericPath!(vibe.core.path.PosixPathFormat).GenericPath, bool) [0x5640ed43772b]
      ../../.dub/packages/vibe-core-1.18.0/vibe-core/source/vibe/core/file.d:548 @safe vibe.core.file.DirectoryWatcher vibe.core.file.watchDirectory(immutable(char)[], bool) [0x5640ed3f7755]
      source/app.d:10 @safe void app.main().__lambda1() [0x5640ed3ebdf9]
      ../../.dub/packages/vibe-core-1.18.0/vibe-core/source/vibe/core/task.d:718 void vibe.core.task.TaskFuncInfo.set!(void function() @safe*).set(ref void function() @safe*).callDelegate(ref vibe.core.task.TaskFuncInfo) [0x5640ed3f072a]
      ../../.dub/packages/vibe-core-1.18.0/vibe-core/source/vibe/core/task.d:739 void vibe.core.task.TaskFuncInfo.call() [0x5640ed40efc5]
      ../../.dub/packages/vibe-core-1.18.0/vibe-core/source/vibe/core/task.d:446 nothrow void vibe.core.task.TaskFiber.run() [0x5640ed40e28b]
      ??:? void core.thread.context.Callable.opCall() [0x5640ed4a6088]
      ??:? fiber_entryPoint [0x5640ed4dbe7b]
FreeSlave commented 3 years ago

Note that if I save Task into variable and then manually call join on it in scope(exit), there're no such warnings when I interrupt the app by Ctrl+C.

import core.time;
import vibe.core.file;
import vibe.core.log;
import vibe.core.task;
import vibe.core.core;

void main()
{
    auto watcherTask = runTask({
        auto watcher = watchDirectory("./test", false);
        while(true)
        {
            DirectoryChange[] changes;
            if (watcher.readChanges(changes, dur!"seconds"(-1)))
            {
                foreach(ref change; changes)
                {
                    logInfo("Changed file: %s\n", change);
                }
            }
        }
    });

    scope(exit) {
        watcherTask.join();
    }

    runApplication();
}
dedupely commented 6 months ago

I can attest to this as well. I have the directory watcher in a runTask like you're doing here and it leaks on shutdown.

s-ludwig commented 6 months ago

As far as I can see, this is a leak that has to be fixed on the user side. All tasks should ideally be terminated before returning from main (e.g. by a task.interrupt(); task.join(); sequence) and in this case, the watcher object will still be alive within the stack of that task, causing the leak. It could be argued that for short lived applications (command line tools) such leaks don't matter, because the OS will clean them up anyway. In that case eventcore could offer an optional compile time version EventCoreSilenceLeakWarnings or similar to just avoid showing the warning to the user.

dedupely commented 6 months ago

@s-ludwig EventCoreSilenceLeakWarnings would be great actually.

s-ludwig commented 5 months ago

Forgot to mention here - the latest versions now have that version flag: https://github.com/vibe-d/eventcore?tab=readme-ov-file#version-identifiers