Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

TaggedUnion assert failure when waiting an event from a different thread #238

Open
yellowsink opened this issue Apr 20, 2024 · 6 comments
Open

Comments

@yellowsink
Copy link

When attempting to wait for an event created on the main thread from a second thread (as far as I can tell from the documentation, that is allowed), the wait() call (not even processevents!) causes an assertion failure in taggedunion.

I've attached a minimal reproduction, but for reference, I encountered this within a more complex project with this demo code: https://github.com/yellowsink/rockhopper/blob/ed05a03/source/app.d

Minimal reproduction code:

import eventcore.core : eventDriver;
import core.thread.osthread : Thread;
import std.stdio : writeln;

void main()
{
	auto drv1 = eventDriver;
	//shared drv1shared = cast(shared) eventDriver; // only necessary to trigger from thread 2, irrelevant

	// making this `shared` has no effect.
	auto ev1_to_2 = drv1.events.create();

	new Thread({
		auto drv2 = eventDriver;

		try {
			drv2.events.wait(ev1_to_2, (_e) nothrow {});
		}
		catch (Exception t)
		{
			writeln(t);
		}
	}).start();//.join(); has no effect
}

library versions:

{
	"fileVersion": 1,
	"versions": {
		"eventcore": "0.9.30",
		"libasync": "0.8.6",
		"memutils": "1.0.10",
		"taggedalgebraic": "0.11.23"
	}
}

exception message (DMD, LDC gives a more compact stack trace):

core.exception.AssertError@../../.dub/packages/taggedalgebraic/0.11.23/taggedalgebraic/source/taggedalgebraic/taggedunion.d(309): Attempting to get type EventSlot from a TaggedUnion with type typeof(null)
----------------
??:? _d_assert_msg [0x5be29787a22c]
../../.dub/packages/taggedalgebraic/0.11.23/taggedalgebraic/source/taggedalgebraic/taggedunion.d:309 inout pure nothrow ref @property @nogc @safe inout(eventcore.drivers.posix.events.EventSlot) taggedalgebraic.taggedunion.TaggedUnion!(eventcore.internal.utils.AlgebraicChoppedVector!(eventcore.drivers.posix.driver.FDSlot, eventcore.drivers.posix.sockets.StreamSocketSlot, eventcore.drivers.posix.sockets.StreamListenSocketSlot, eventcore.drivers.posix.sockets.DgramSocketSlot, eventcore.drivers.posix.dns.DNSSlot, eventcore.drivers.posix.watchers.WatcherSlot, eventcore.drivers.posix.events.EventSlot, eventcore.drivers.posix.signals.SignalSlot, eventcore.drivers.posix.pipes.PipeSlot).AlgebraicChoppedVector.U).TaggedUnion.value!(eventcore.drivers.posix.events.EventSlot).value() [0x5be297845a1b]
../../.dub/packages/taggedalgebraic/0.11.23/taggedalgebraic/source/taggedalgebraic/taggedalgebraic.d:767 pure nothrow ref @nogc @safe inout(eventcore.drivers.posix.events.EventSlot) taggedalgebraic.taggedalgebraic.get!(eventcore.drivers.posix.events.EventSlot, eventcore.internal.utils.AlgebraicChoppedVector!(eventcore.drivers.posix.driver.FDSlot, eventcore.drivers.posix.sockets.StreamSocketSlot, eventcore.drivers.posix.sockets.StreamListenSocketSlot, eventcore.drivers.posix.sockets.DgramSocketSlot, eventcore.drivers.posix.dns.DNSSlot, eventcore.drivers.posix.watchers.WatcherSlot, eventcore.drivers.posix.events.EventSlot, eventcore.drivers.posix.signals.SignalSlot, eventcore.drivers.posix.pipes.PipeSlot).AlgebraicChoppedVector.U).get(ref inout(taggedalgebraic.taggedalgebraic.TaggedAlgebraic!(eventcore.internal.utils.AlgebraicChoppedVector!(eventcore.drivers.posix.driver.FDSlot, eventcore.drivers.posix.sockets.StreamSocketSlot, eventcore.drivers.posix.sockets.StreamListenSocketSlot, eventcore.drivers.posix.sockets.DgramSocketSlot, eventcore.drivers.posix.dns.DNSSlot, eventcore.drivers.posix.watchers.WatcherSlot, eventcore.drivers.posix.events.EventSlot, eventcore.drivers.posix.signals.SignalSlot, eventcore.drivers.posix.pipes.PipeSlot).AlgebraicChoppedVector.U).TaggedAlgebraic)) [0x5be2978459b4]
../../.dub/packages/eventcore/0.9.30/eventcore/source/eventcore/internal/utils.d-mixin-311:316 pure nothrow ref @property @nogc @safe eventcore.drivers.posix.events.EventSlot eventcore.internal.utils.AlgebraicChoppedVector!(eventcore.drivers.posix.driver.FDSlot, eventcore.drivers.posix.sockets.StreamSocketSlot, eventcore.drivers.posix.sockets.StreamListenSocketSlot, eventcore.drivers.posix.sockets.DgramSocketSlot, eventcore.drivers.posix.dns.DNSSlot, eventcore.drivers.posix.watchers.WatcherSlot, eventcore.drivers.posix.events.EventSlot, eventcore.drivers.posix.signals.SignalSlot, eventcore.drivers.posix.pipes.PipeSlot).AlgebraicChoppedVector.FullField.event() [0x5be2978384ab]
../../.dub/packages/eventcore/0.9.30/eventcore/source/eventcore/drivers/posix/events.d:251 nothrow @nogc @trusted eventcore.drivers.posix.events.EventSlot* eventcore.drivers.posix.events.PosixEventDriverEvents!(eventcore.drivers.posix.epoll.EpollEventLoop, eventcore.drivers.posix.sockets.PosixEventDriverSockets!(eventcore.drivers.posix.epoll.EpollEventLoop).PosixEventDriverSockets).PosixEventDriverEvents.getSlot(eventcore.driver.EventID).__lambda2() [0x5be29782adf2]
../../.dub/packages/eventcore/0.9.30/eventcore/source/eventcore/drivers/posix/events.d:251 nothrow @nogc @safe eventcore.drivers.posix.events.EventSlot* eventcore.drivers.posix.events.PosixEventDriverEvents!(eventcore.drivers.posix.epoll.EpollEventLoop, eventcore.drivers.posix.sockets.PosixEventDriverSockets!(eventcore.drivers.posix.epoll.EpollEventLoop).PosixEventDriverSockets).PosixEventDriverEvents.getSlot(eventcore.driver.EventID) [0x5be29782adb8]
../../.dub/packages/eventcore/0.9.30/eventcore/source/eventcore/drivers/posix/events.d:261 nothrow @nogc @safe bool eventcore.drivers.posix.events.PosixEventDriverEvents!(eventcore.drivers.posix.epoll.EpollEventLoop, eventcore.drivers.posix.sockets.PosixEventDriverSockets!(eventcore.drivers.posix.epoll.EpollEventLoop).PosixEventDriverSockets).PosixEventDriverEvents.isInternal(eventcore.driver.EventID) [0x5be29782ae54]
../../.dub/packages/eventcore/0.9.30/eventcore/source/eventcore/drivers/posix/events.d:155 nothrow @nogc @safe void eventcore.drivers.posix.events.PosixEventDriverEvents!(eventcore.drivers.posix.epoll.EpollEventLoop, eventcore.drivers.posix.sockets.PosixEventDriverSockets!(eventcore.drivers.posix.epoll.EpollEventLoop).PosixEventDriverSockets).PosixEventDriverEvents.wait(eventcore.driver.EventID, void delegate(eventcore.driver.EventID) nothrow @safe) [0x5be29782a92f]
source/app.d:26 nothrow void app.main().__lambda3() [0x5be2977fbe91]
??:? void core.thread.context.Callable.opCall() [0x5be29787f73c]
??:? thread_entryPoint [0x5be29787f21a]
??:? [0x786ce035f559]
??:? [0x786ce03dca3b]
@yellowsink
Copy link
Author

If it is simply the case that threads may only wait for events created on their own thread, I think this should be documented more clearly, but that also would significantly increase the difficulty of syncing threads so I'm hoping this is just a bug that can be fixed!

yellowsink added a commit to yellowsink/rockhopper that referenced this issue Apr 20, 2024
@s-ludwig
Copy link
Member

The problem here is that each event ID is only valid for the event driver instance that created it. So in order to wait from another thread, you have to pass the main thread's eventDriver as cast(shared)eventDriver to the other thread and then call the shared overload of wait there. I'll add some documentation for this.

@yellowsink
Copy link
Author

ah! I was aware of shared trigger but not shared wait. doesn't this mean that you'd need to use a shared processevents too, though?
I suppose the only way to do what I want is to make sure it's constructed on the second thread... should be doable

@s-ludwig
Copy link
Member

Oh wait, you are right, I misremembered that. There is indeed no shared wait! So it actually needs to be turned around to work and the waiting thread needs to create the event. I'm not quite sure whether this is something that can be improved without introducing additional locking within the driver, which would certainly impair performance.

@yellowsink
Copy link
Author

I can probably work around this in my wrapper struct I have - I can keep a map of thread ids to (eventid, shared(eventdriver)) and that should work, but I suppose if making this work would result in a general slowdown for usage of events in eventcore its most likely better placed as a hit taken in user code than there.

@yellowsink
Copy link
Author

I can probably work around this in my wrapper struct I have

I've got this working - so I suppose it's really just a docs change that's needed to clarify the requirement to wait on the same thread as create

yellowsink added a commit to yellowsink/rockhopper that referenced this issue Apr 21, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants