-
-
Notifications
You must be signed in to change notification settings - Fork 1.6k
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
Extract platform-specifics of Fiber, Thread and EventLoop #6955
Extract platform-specifics of Fiber, Thread and EventLoop #6955
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What's actually abstracted is mmap
, which has more usages than allocating a stack for fibers. For example I use them in both my GC and my MT scheduler.
I'd prefer an Crystal::System::MemoryMap
struct, and adding Windows support right away (File Mapping) to validate the abstraction model.
It doesn't abstract mmap, it abstracts a certain usage of mmap, particularly, allocating stacks. I don't think that should be the same abstraction as other mmap usages. |
@ysbaddaden Sure, it can be renamed to be more general. What about Adding the windows implementation right away is not an issue. I already have that code. It compiles but I can't validate it, because event handling hasn't been ported. I don't think it makes much sense to add dedicated specs for this? |
f4e7ced
to
451c5ba
Compare
I added the win32 implementation as far as I could get. I can't figure out the assembly for actually swapping the context on x86_64-win32. This is really not my area of expertise. I'd be happy if somebody can take over this part. You guys now much better what to do. |
4c8b870
to
226c330
Compare
226c330
to
c63ace5
Compare
Good job at adding Win32 support overall. I didn't review correctly, but that looks nice! I stand to my original point: abstracting
What differs are subsequent calls, but the Also, detecting a thread's stack should be the responsibility of Thread, not Fiber, that could ask the thread or be passed by the Thread when it initializes its main Fiber —I missed that in the stack overflow detection pull request. Last but not least: I didn't know what I was doing while meddling with the arch-specific assembly, but I searched for reference, experimented with gdb and registers, and eventually learned a lot. Hint: look at ldc coroutines (D compiler based on LLVM) and search for win32 callee saved registers. For example https://en.wikipedia.org/wiki/X86_calling_conventions |
Assuming that a mmap even exists on the target platform is a mistake. mmap is a hugely complex syscall and the flags you want to use even if all kernels supported the same flags would differ depending on kernel idiosyncrasies. "Allocate this amount of heap memory from the OS and return a pointer to the start" is a very different operation to "Allocate a stack" and there's no reason to put them through the same method. There's no need to expose madvise and mprotect instead of just exposing "give me a stack".
|
@RX14 Do you have an example of a target that doesn't implement anonymous memory mappings, that allocates pages when they're accessed? I don't intend to have a complete mmap interface, but the minimum we'll need in core/stdlib. See for example: ysbaddaden@29547dc |
@ysbaddaden Your example looks quite complicated. It adds a lot of specifics of the memory mapping API to the general Crystal::System::MemoryMapping.new(STACK_SIZE, :READ_WRITE, :STACK).tap do |mapping|
mapping.advise(:NOHUGEPAGE)
mapping.protect(GUARD_SIZE, :NONE)
end I'd prefer to keep the interface between |
Windows doesn't allow memory overcommit, which limits the number of fibers to be ((memory + pagefile - other programs) / 8MiB). So windows may not actually allocate pages when they're accessed, but it does memory accounting as if all pages were allocated immediately. So to answer what I think you're implying: no, I don't have any idea how to properly implement fibers on windows apart from go-style growable stacks. |
Allocating a fiber stack is an operation which you can easily stub, or make special platform-specific alterations for. mmap is a complex unix interface with a lot of complexity and a lot of assumptions. |
I'd still like a
And ideally:
This could allow fibers to have differently sized stacks —defined manually or better automatically thanks to some compiler analysis, to reduce memory pressure on Win32 and virtual memory on POSIX. We could have both a |
@ysbaddaden I'd be fine with a |
@ysbaddaden any resolution on this topic? Its been a couple of months since the last comment and I was wondering if there were other discussions on this offline. Would be nice to move this PR along. |
@rishavs Finding an agreement on the interface is not really an urging matter as it won't really make a noticeable change from a usage point of view. The important thing is to figure out the assembly code for a fiber switch on win32. That will have an impact as it brings us closer to running fibers on windows. That being said, it would of course be great if we could settle on the interface and proceed from there. |
dadc1c0
to
07ab99b
Compare
I've rebased this PR on current master and also took another stab on the context swap implementation. The major problem is actually just #7955. The context swap implementation in the Thank you so much @cfsamson for investigating and finding the culprit. Your book is really interesting. I'm really glad there is finally help from someone with expertise on windows 😍 Now I've updated the feature/fiber-win32 branch. Context switches are basically working now =) I also added the XMM and TIB registers as suggested by @cfsamson When running the concurrent_spec, there is a failure trying to resume a non-resumable main fiber. This might be related to channels. I'm not sure right now. But this is already a big step ahead 🎉 I'd suggest to continue with reviews on this PR and after it is merged, I'll open a new one adding the win32 implementation. |
d388a7d
to
1a70510
Compare
1a70510
to
972b7a8
Compare
972b7a8
to
40e31c5
Compare
I've reduced the scope of this PR to refactoring and extracting the platform-specific implementations. Meanwhile, I've added an |
Please close this PR or rebase it to match your last branch with the wIn32 context switch! It's much better than the preliminary work here, and I only have a few remarks. It won't delay the merge, and we'll have fibers working on win32! Huge feat! In fact what I'm not really fond of are these PR commits. I'd prefer thread/pthread.cr, thread/win32.cr, thread/pthread/mutex.cr files, each fully implementing their "public" interface, instead of extracting generic Thread and Thread::Mutex classes. That would add duplication, but readability should improve. |
It's also the case that refactors like this will probably conflict much more against the current work on parallelism and so it's unlikely that they will get merged, or they will delay parallelism more. |
@ysbaddaden
I'm not sure what you mean. There are no generic classes of either of them. @asterite |
This PR mostly brings stubs without the win32 implementation of Fiber stacks and x86_64 context switch, those are huge progresses! That helps counterbalance the changes and conflicts with other branches (MT) that this PR introduces. About the rework: I meant that POSIX and Win32 don't need to share a base Thread class. The amount of duplicated code isn't large enough to justify the split. That would allow them to have their own internal details, so we treat them as "opaque classes". I'd also like this rework to settle on where we should put specific classes, namely Being system specific, I suppose they should be moved under For threads, I guess they should be For the event loop, maybe Just a question: would it be hard to bring real win32 thread support, instead of bringing a stub? I know that's not needed to implement fibers, but threads aren't needed on POSIX either, and it would be awesome to have a basic support for them. |
May I ask how you plan to implement IOCP support? And where the epoll/kqueue/iocp based event loop plays into this? Maybe I'm wrong but creating a new thread itself looks pretty easy using the CreateThread WinApi function, but I don't have the answer to what setup is required beyond that to fit it into Crystals thread support. |
@cfsamson we use libevent for now, which leverages epoll/kqueue for us. I'd like to use on Win32 too, but it may be more complex to integrate libevent than using IOCP directly on Win32. Basically, with we juste create resume events (sleep) and read/write ready events on file descriptors, that fit both File and Socket on POSIX, but don't quite map to windows sockets an file handles. |
@ysbaddaden I've opened #7995 which has everything in I think this PR can be closed. |
@ysbaddaden OK, thanks. Seems that libevent abstracts over IOCP also pretty effectively when using |
I don't want to rely on libevent for windows. It will not work. We must implement our own event loop from scratch on windows for any kind of sane implementation. |
This is a step to prepare
Fiber
for Windows support.