After an evaluation, GNOME has moved from Bugzilla to GitLab. Learn more about GitLab.
No new issues can be reported in GNOME Bugzilla anymore.
To report an issue in a GNOME project, go to GNOME GitLab.
Do not go to GNOME Gitlab for: Bluefish, Doxygen, GnuCash, GStreamer, java-gnome, LDTP, NetworkManager, Tomboy.
Bug 597662 - Make new external plugin scanner work in Windows
Make new external plugin scanner work in Windows
Status: RESOLVED OBSOLETE
Product: GStreamer
Classification: Platform
Component: gstreamer (core)
git master
Other Windows
: Normal major
: git master
Assigned To: GStreamer Maintainers
GStreamer Maintainers
playback
Depends on:
Blocks:
 
 
Reported: 2009-10-07 09:51 UTC by LRN
Modified: 2018-11-03 12:13 UTC
See Also:
GNOME target: ---
GNOME version: ---


Attachments
Fixes recent changes incompatible with Windows (34.58 KB, patch)
2009-10-07 09:52 UTC, LRN
rejected Details | Review
Uses _commit() instead of fsync(), _cwait() to wait for pluginloader child (2.50 KB, patch)
2009-10-07 21:54 UTC, LRN
rejected Details | Review
Uses _commit() instead of fsync() on win32 (1.20 KB, patch)
2009-10-16 12:51 UTC, LRN
none Details | Review
Fixes win32 private dll handle access issue (741 bytes, patch)
2009-10-16 12:52 UTC, LRN
none Details | Review
Removes a FIXME about using DuplicateHandle on win32 (1.37 KB, patch)
2009-10-16 12:53 UTC, LRN
none Details | Review
Uses _cwait() to wait for process exit on win32 (1.04 KB, patch)
2009-10-16 12:53 UTC, LRN
none Details | Review
Uses commit() instead of fsync() on win32 (1.20 KB, patch)
2009-10-31 09:49 UTC, LRN
none Details | Review
Fix win32 module call path (881 bytes, patch)
2009-10-31 09:50 UTC, LRN
none Details | Review
Use dup() and dup2() on win32 (1.37 KB, patch)
2009-10-31 09:50 UTC, LRN
none Details | Review
Use _cwait() to wait for child process termination on win32 (1.04 KB, patch)
2009-10-31 09:51 UTC, LRN
none Details | Review
Support for win32 named pipes (23.97 KB, patch)
2009-10-31 09:52 UTC, LRN
none Details | Review
native win32 pipe I/O and process spawning (62.90 KB, patch)
2009-10-31 09:52 UTC, LRN
none Details | Review
Whitespace fix (1.64 KB, patch)
2009-10-31 09:53 UTC, LRN
none Details | Review
[gstpoll] Native Win32 named pipe I/O (39.69 KB, patch)
2009-11-12 11:27 UTC, LRN
none Details | Review
[gstpluginloader] Native Win32 process spawning and I/O (25.06 KB, patch)
2009-11-12 11:28 UTC, LRN
none Details | Review
[gstpluginloader] Disable external pluginloader on Windows (2.43 KB, patch)
2009-11-12 11:29 UTC, LRN
none Details | Review
Limited POSIX-compatible I/O and process spawning API, implemented on top of WinAPI (171.91 KB, patch)
2009-11-28 02:52 UTC, LRN
needs-work Details | Review
Fix win32 compilation (670 bytes, patch)
2010-01-08 20:02 UTC, Andoni Morales
none Details | Review
Fix win32 compilation (1.51 KB, patch)
2010-01-08 21:30 UTC, Andoni Morales
committed Details | Review

Description LRN 2009-10-07 09:51:44 UTC
1) _priv_gst_dll_handle is not used properly
2) fsync is not available on Windows

A patch attached fixes both (however it is rather intrusive, since it hooks gnulib in).
Comment 1 LRN 2009-10-07 09:52:18 UTC
Created attachment 144941 [details] [review]
Fixes recent changes incompatible with Windows
Comment 2 Michael Smith 2009-10-07 17:35:37 UTC
Comment on attachment 144941 [details] [review]
Fixes recent changes incompatible with Windows

Seriously? This is awful, it's full of object files and libtool gunk, and I have no idea what the real changes needed are.

Pulling in new libraries is not ok either.
Comment 3 Edward Hervey 2009-10-07 18:01:29 UTC
+1 on mike's comment.

Split all of it up (the one that fixes using _priv_gst_dll_handle, and another one for fsync fixing), do not pull in external libraries, do not touch libtool.
Comment 4 LRN 2009-10-07 21:54:28 UTC
Created attachment 144999 [details] [review]
Uses _commit() instead of fsync(), _cwait() to wait for pluginloader child

Note that while _cwait() is supposed to be a correct function to be used, pluginloader still fails (because it tries to use GstPoll with lowlevel IO file descriptors, returned by _pipe(), which does not work on Windows).

Also, it is not straightforward for me to separate _priv_gst_dll_handle fix from fsync fix, because both are required to compile GStreamer (and sending a patch that leaves the trunk in incompilable state is bad!).
Comment 5 Michael Smith 2009-10-07 22:11:39 UTC
Comment on attachment 144999 [details] [review]
Uses _commit() instead of fsync(), _cwait() to wait for pluginloader child

So this patch just makes it compile, not actually work? That's not too helpful either.

The problems here look much more pervasive - there are a whole lot of serious win32 issues throughout this code (cross-CRT issues, etc.).

It really needs the process/pipe management stuff factored out, and then a completely separate win32 implementation written using the native win32 APIs - doing it with the glib APIs is unlikely to work well.

I can look at doing that some time soonish, probably.
Comment 6 LRN 2009-10-09 09:52:08 UTC
1) It works. When external loader fails, it falls back to the old plugin loader and still works.

2) Problem is that PluginLoader uses g_spawn*() to create the subprocess and pipes to communicate with it, and wraps these pipes into GstPoll. The pipes returned by g_spawn_async_with_pipes() are lowlevel CRT pipes, (_pipe() and friends) and do not support asynchronous I/O. With WinAPI pipes (CreateNamedPipe() and friends) it should be possible to do asynchronous I/O and thus it should be possible to wrap them into GstPoll (after GstPoll is extended to work with these pipes), but that also means either implementing a version of g_spawn*() and friends that work with such pipes (which is what glib developers should have done), or not using g_spawn*() at all.

As a sidenote, the same goes for files. With CRT file I/O you can't do asynchronous I/O (AFAIK, i may be wrong), but with WinAPI file I/O you can. In the end the usage of WinAPI I/O (as it was done with sockets in GstPoll) can lead to uniform higher-level I/O API that supports async I/O, events and various stuff. Of course it also means that there will be either separate object files with implementation for *nix and for Win32, or a lot of #ifdefs (kinda like GstPoll at the moment).
Comment 7 LRN 2009-10-16 12:51:46 UTC
Created attachment 145596 [details] [review]
Uses _commit() instead of fsync() on win32
Comment 8 LRN 2009-10-16 12:52:32 UTC
Created attachment 145597 [details] [review]
Fixes win32 private dll handle access issue
Comment 9 LRN 2009-10-16 12:53:22 UTC
Created attachment 145598 [details] [review]
Removes a FIXME about using DuplicateHandle on win32
Comment 10 LRN 2009-10-16 12:53:54 UTC
Created attachment 145599 [details] [review]
Uses _cwait() to wait for process exit on win32
Comment 11 LRN 2009-10-16 12:58:03 UTC
OK, i've managed to break the patch into a few separate patches (also updated it to be against current HEAD).
Comment 12 Michael Smith 2009-10-16 17:18:43 UTC
The cwait one looks like it probably isn't ok.

The others look ugly but acceptable. 

I'm not sure why the code does fsync at all - maybe that can just be removed?
Comment 13 LRN 2009-10-16 18:18:19 UTC
_cwait() should work on process identifiers returned by _spawn*(), see
http://msdn.microsoft.com/en-us/library/zb9ehy71%28VS.80%29.aspx

As for the necessity of fsync() - ask thaytan.
Comment 14 Michael Smith 2009-10-16 18:27:34 UTC
I read the documentation. We don't call it on something returned by _spawn(), we call it on something returned from glib. This is presumably unsafe, due to cross-CRT issues.
Comment 15 LRN 2009-10-31 09:49:39 UTC
Created attachment 146622 [details] [review]
Uses commit() instead of fsync() on win32
Comment 16 LRN 2009-10-31 09:50:08 UTC
Created attachment 146623 [details] [review]
Fix win32 module call path
Comment 17 LRN 2009-10-31 09:50:49 UTC
Created attachment 146624 [details] [review]
Use dup() and dup2() on win32
Comment 18 LRN 2009-10-31 09:51:26 UTC
Created attachment 146625 [details] [review]
Use _cwait() to wait for child process termination on win32
Comment 19 LRN 2009-10-31 09:52:10 UTC
Created attachment 146626 [details] [review]
Support for win32 named pipes
Comment 20 LRN 2009-10-31 09:52:52 UTC
Created attachment 146627 [details] [review]
native win32 pipe I/O and process spawning
Comment 21 LRN 2009-10-31 09:53:15 UTC
Created attachment 146628 [details] [review]
Whitespace fix
Comment 22 LRN 2009-10-31 10:04:23 UTC
Phew. Sorry for the tail of old patches, but i did not master git well enough to cut it off (or maybe i've been too lazy to do that).

Anyway, here's the proposal: use native process spawning (CreateProcess()) and pipe I/O (CreateNamedPipe(), CreateFile(), ReadFile(), WriteFile() and friends).

The advantage is that it has nothing to do with CRT and is not affected by CRT incompatibility. And it is not affected by the fact that msvcrt is crippled and cannot select() on non-socket descriptors.
Basically this patch does roughly the same that [i suspect (since i don't know for sure)] cygwin does - implements more-or-less POSIX-compatible synchronous file I/O using WinAPI. Not completely, mind you. It doesn't implement select() or poll(), because gstpoll is full of win32 #ifdefs already and is perfectly capable of selecting native handles in native way.

It's kinda ugly, because i left process spawning functionality (code ripped from glib) in gstpluginloader.c, while it should have got a separate file, and had to leave gst_poll_fd_read and gst_poll_fd_write in gstpoll.c, while cross-platform I/O should not have anything in common with gstpoll (since i didn't implement poll/select, gstpoll has to dig deep into the I/O to poll the handles, that is why the code is still tied to gstpoll and why I/O is implemented in gstpoll context).

Also, a few pieces of commented code here and there. And a few junk code that does nothing. And some parts are broken/unimplemented.
I've tried to keep it backward-compatible for winsock, that is - it should work with sockets on Windows the same way it worked before. In theory. Didn't test that.

But bottom line is, this code works - at least i was able to run gst-inspect-0.10 without crashing and got 186 plugins (1 blacklist entry not shown), 919 features.
Comment 23 LRN 2009-11-12 11:26:22 UTC
Separated dll handle issue into https://bugzilla.gnome.org/show_bug.cgi?id=601668 , since it is not really linked to pluginloader (other than the fact that it is a blocker too).

Below are three pluginloader patches:

First two are native win32 pipe I/O support for gstpoll and the modification for gstpluginloader to use improved gstpoll and native win32 process spawning. The comments above are still applicable.

Third patch is an alternative to the first pair. It makes gstregistry skip gstpluginloader altogether, and also adds a few bogus #defines to gstpluginloader to make it compilable on Windows. Pluginloader remains broken, of course, but since its code is never really executed on Windows due to gstregistry changes (unless i've missed some calls to pluginloader elsewhere), it doesn't really matters whether it works or not.
Comment 24 LRN 2009-11-12 11:27:35 UTC
Created attachment 147559 [details] [review]
[gstpoll] Native Win32 named pipe I/O
Comment 25 LRN 2009-11-12 11:28:19 UTC
Created attachment 147561 [details] [review]
[gstpluginloader] Native Win32 process spawning and I/O
Comment 26 LRN 2009-11-12 11:29:55 UTC
Created attachment 147563 [details] [review]
[gstpluginloader] Disable external pluginloader on Windows

This patch and patches #147559 and #147561 are mutually exclusive.
Comment 27 LRN 2009-11-28 02:52:40 UTC
Created attachment 148632 [details] [review]
Limited POSIX-compatible I/O and process spawning API, implemented on top of WinAPI

It's big, it's bad...it works.

I've made it like this:
1) Look up POSIX specs
2) Look up WinAPI specs
3) Implement
4) Test on pluginloader (which was the focus of this patch)
5) Fix until pluginloader works
5) Test on unit tests
6) Fix until unit tests affected by it do work [again (because some of them weren't working in the first place)]

Which means that in its present condition this code is correct (mostly) in relation to GStreamer code and its unit tests, but not POSIX as it is. That is why i left it in form of #ifdefs instead of replacing POSIX/glibc syscalls with something like gst_io_read() or whatever. The intention is for programmers to be painfully aware of the fact that there are two different I/O interfaces with roughly the same logic, but with possible differences in behaviour in some cases (in which case it must be fixed).

Some things are not implementable (at least i didn't find a way to do it). For example, it is not possible to check a pipe for closiness without actually reading or writing data (writing or reading 0 bytes doesn't help). Because of that gst_win32_prepare_for_poll does a clever thing - it looks at polled events: if there are no events other than POLLHUP (FD_CLOSE), it reads or writes (depends on handle access) 1 byte. Normally that would screw up the communication process, but since application obviously expects pipe to be closed, it doesn't matter if we write garbage or waste data by reading it. But application should be aware of it to avoid unpleasant surprises.

Another thing - i didn't do a descriptor table. Which means that there are no '0', '1' and '2' descriptors matching stdin/out/err. This is obvious in some of the unit tests where two functions rely on the fact that fd = 1 is always the same fd. To make it work, i had to create a wrapper (because this is how it works) WinFd structure in one function and pass it to the other function via global variable to make sure that the other function uses the same pointer.

Hacky things:

return values (especially the painful 64-bit file seeking). Some functions may return signed values instead of unsigned. Be careful.

fd as gpointer. It might be dangerous because while gpointer is big enough to hold any fd, it is unsigned, while fd is signed. If you see '== (gpointer) -1' - it really was '< 0'.

Some unit tests will continue to fail. I guess they were failing before too. Unless i know exactly what exactly is being tested (tests are known to produce a lot of warnings/errors because they sometimes do bad things on purpose, so just fixing errors is not correct - i have to know which errors are intended and which aren't) i can't rectify that.
Comment 28 Julien Isorce 2009-12-08 15:10:19 UTC
Hi tried the patch-148632 and this is what I got:

Program received signal SIGSEGV, Segmentation fault.
0x6b72f919 in gst_win32_fsync (wfd=0xffffffff) at gstwin32io.c:278
278       FlushFileBuffers (wfd->fd);
(gdb) bt
  • #0 gst_win32_fsync
    at gstwin32io.c line 278
  • #1 plugin_loader_free
    at gstpluginloader.c line 165
  • #2 clear_scan_context
    at gstregistry.c line 994
  • #3 gst_update_registry
    at gstregistry.c line 1490
  • #4 init_post
    at gst.c line 765
  • #5 g_option_context_parse
    from C:\msys\1.0\local\bin\libglib-2.0-0.dll
  • #6 main
    at gst-inspect.c line 1499


Steps:
clean env and old gstreamer installation
make
make install
gst-inspect-0.10
Comment 29 LRN 2009-12-08 18:53:39 UTC
Can't reproduce.

Apparently, loader->fd_w.fd is left at "(gpointer) -1" (the value it is initialized with).

The only place where fd_w.fd is altered is the call to gst_win32_spawn_async_with_named_pipes(). If fd_w.fd is left at 0xffffffff after that call, it means that do_spawn_with_named_pipes() fails to create a pipe. But it doesn't, because if it did, it would have returned FALSE.

Rather, i think it means that plugin_loader_free() is called for a pluginloader that was initialized (which is done at creation time), but that never had a chance to call gst_plugin_loader_try_helper(), so fd_w.fd remained 0xffffffff.

Which is very confusing, because gst_update_registry() never calls clear_scan_context() and thus plugin_loader_free (which it does, according to your backtrace). And even if it did, clear_scan_context() shouldn't try to destroy pluginloader, unless context->helper is non-NULL, which should only happen when gst_plugin_loader_try_helper() was called.

The fact that it comes to plugin_loader_free() being called for a pluginloader without a helper process is clearly a bug. However as far as i can see, calling fsync() with invalid FD is not an error (sets errno to BADF, but that's all it does), so here's a fixed version of gst_win32_fsync():

gint
gst_win32_fsync (WinFd *wfd)
{
  if (G_UNLIKELY (!wfd || wfd->fd == (gpointer) -1))
  {
    errno = EBADF;
    return -1;
  }

  FlushFileBuffers (wfd->fd);
  return 0;
}

P.S. Don't forget to fix the prototype in gstwin32io.h

P.P.S. It might be a good idea to further improve this function by checking for FlushFileBuffers return value: if it's zero, GetLastError() should be called and errno set appropriately.
Comment 30 Julien Isorce 2009-12-09 10:00:45 UTC
hi, it didn't resolve the crash:

Program received signal SIGSEGV, Segmentation fault.
0x6b72f91d in gst_win32_fsync (wfd=0xffffffff) at gstwin32io.c:278
278       if (G_UNLIKELY (!wfd || wfd->fd == (gpointer) -1))
(gdb) bt
  • #0 gst_win32_fsync
    at gstwin32io.c line 278
  • #1 plugin_loader_free
    at gstpluginloader.c line 165
  • #2 clear_scan_context
    at gstregistry.c line 994
  • #3 gst_update_registry
    at gstregistry.c line 1490
  • #4 init_post
    at gst.c line 765
  • #5 g_option_context_parse
    from C:\msys\1.0\local\bin\libglib-2.0-0.dll
  • #6 main
    at gst-inspect.c line 1499

but if (G_UNLIKELY (!wfd || wfd == (gpointer) -1 || wfd->fd == (gpointer) -1))
yes

in gst_win32_close you are checking wfd == (gpointer) -1, why not in gst_win32_fsync so.

Well now gst-inspect-0.10 does not crash.

$ gst-inspect-0.10
coreindexers:  memindex: A index that stores entries in memory
coreelements:  multiqueue: MultiQueue
coreelements:  typefind: TypeFind
coreelements:  tee: Tee pipe fitting
coreelements:  filesink: File Sink
coreelements:  queue2: Queue 2
coreelements:  queue: Queue
coreelements:  identity: Identity
coreelements:  filesrc: File Source
coreelements:  fdsink: Filedescriptor Sink
coreelements:  fdsrc: Filedescriptor Source
coreelements:  fakesink: Fake Sink
coreelements:  fakesrc: Fake Source
coreelements:  capsfilter: CapsFilter
staticelements:  bin: Generic bin
staticelements:  pipeline: Pipeline object

Total count: 3 plugins, 16 features

By the way, I am using msys+mingw in a winxp virtualbox client, and host is a linux. gstreamer checkout is on the host and the dir is shared to the client.
Maybe it can explain this particular case that caused this crash.
Comment 31 LRN 2009-12-09 19:14:48 UTC
Sorry, my bad (about checking wfd->fd instead of just wfd).

As for what caused the crash - i am clueless, really. You could try putting some log-points into gstregistry and pluginloader to see when a pluginloader object is created and when it is destroyed and what is being done with it in between. If there is a reason why a pluginloader is constructed and then freed without being used, you'll see it. Otherwise there's a bug in my own gstwin32io.c 

Sadly, i only have Windows host (and creating a Linux VBox that runs a Windows VBox is kinda...weird), so for me it is still unreproducible.

By the way, i hope no one is offended by the fact that this code logs at warning level? :)
Comment 32 Andoni Morales 2010-01-08 20:02:20 UTC
Created attachment 151059 [details] [review]
Fix win32 compilation

If we just need something that compiles, to fallback to old behaviour this should work for the moment.
Comment 33 Andoni Morales 2010-01-08 21:30:02 UTC
Created attachment 151068 [details] [review]
Fix win32 compilation

I haven't seen LRN first patch :/
Mine is similar but including <io.h> instead of redifining _close, etc...
I have also disabled the plugin loader as he does.
Comment 34 LRN 2010-01-09 02:40:44 UTC
The long-term solution is to wait until certain version of GLib and use GPoll instead of GstPoll.
GstPoll+my_big_patch and GPoll are different in following ways:
1) My poll uses asynchronous pipes (when coupled with my implementation of spawn()), which work without threads (synchronous pipes + threads are also supported). GPoll uses normal synchronous CRT pipes with threads for anynchronousness
2) My implementation of spawn() uses Windows process handles instead of process IDs, thus eliminating the problem with CRT incompatibility (process ID returned by g_spawn*() are supposedly only waitable/closeable with waitpid/close of the same version of MSVCRT). It might be fixable on GLib side if they provide g_close() and g_waitpit() (do they?)
3) My patch doesn't work with GSource at all, because GSource polls sources internally and there is no way to substitute that poll with my own.
4) My patch is my patch, GPoll is supposedly maintained by GLib developers
5) Migration from GstPoll to GPoll is easier than migration from GstPoll to GstPoll+my_big_patch (especially considering the lack of GSource integration)
Comment 35 Tim-Philipp Müller 2010-01-18 12:51:38 UTC
LRN: Andoni's patch seems marginally cleaner to me - does it make things work for you as well?
Comment 36 Tim-Philipp Müller 2010-01-20 01:47:40 UTC
Comment on attachment 151068 [details] [review]
Fix win32 compilation

Committed (after making sure to include gst_private.h which includes glib.h before so that G_OS_WIN32 is defined properly - how did it work right before without that, I wonder - did you test the patch?)
Comment 38 Sebastian Dröge (slomo) 2013-03-06 07:37:34 UTC
Is there still something necessary to do here?
Comment 39 LRN 2013-03-06 07:59:49 UTC
Plugin loader still doesn't work on W32 (presumably), and is still disabled. The patch that was committed simply disables it unconditionally on W32.

Honestly, i haven't thought about this problem for months. Also didn't check what glib was doing with g_spawn() and GPoll...
Comment 40 Sebastian Dröge (slomo) 2013-07-24 08:14:14 UTC
I think the solution here would be to "just" exec() the plugin scanner and use a different IPC mechanism, e.g. a TCP socket, to talk between main process and plugin scanner.
Comment 41 Sebastian Dröge (slomo) 2013-07-24 08:14:57 UTC
Comment on attachment 148632 [details] [review]
Limited POSIX-compatible I/O and process spawning API, implemented on top of WinAPI

At least needs to be rebased to git master, but also should be split a bit. Such a extremely large patch is simply not reviewable in reasonable time.
Comment 42 GStreamer system administrator 2018-11-03 12:13:35 UTC
-- GitLab Migration Automatic Message --

This bug has been migrated to freedesktop.org's GitLab instance and has been closed from further activity.

You can subscribe and participate further through the new bug through this link to our GitLab instance: https://gitlab.freedesktop.org/gstreamer/gstreamer/issues/11.