Reputation: 16435
Some background on why I'm asking this. I asked this question a few hours ago
When a goroutine blocks on I/O how does the scheduler identify that it has stopped blocking?
which had the answer
All I/O must be done through syscalls, and the way syscalls are implemented in Go, they are always called through code that is controlled by the runtime. This means that when you call a syscall, instead of just calling it directly (thus giving up control of the thread to the kernel), the runtime is notified of the syscall you want to make, and it does it on the goroutine's behalf. This allows it to, for example, do a non-blocking syscall instead of a blocking one (essentially telling the kernel, "please do this thing, but instead of blocking until it's done, return immediately, and let me know later once the result is ready"). This allows it to continue doing other work in the meantime.
So from my understanding, what the golang scheduler does is that it makes sure not to get hung up spending time on threads waiting for I/O operations. Instead, it somehow defers that responsibility to the kernel.
However, I want to get a deeper understanding of the process because there a lot of things that are unclear to me.
Right now this is my understanding, which may potentially be completely wrong.
What I'm struggling to understand is how the I/O operation is done without creating another thread, and how the kernel actually "knows" the I/O operation is done. Is it through polling or is there some kind of interrupt system in place?
I hope this makes some semblance of sense. I'm very new to concepts that are this low level.
Upvotes: 2
Views: 324
Reputation: 2448
The KERNEL below means "kernel side". It includes OS kernel code + loaded drivers.
Given you have a TCP connection to a remote server. Here is an example how Kernel handles asynchronous write/read TCP stream.
When you send a byte array to TCP stream, kernel will puts the buffer stream in RAM and control the DMA system to copy the buffer to networking card. When DMA done its job, there is an interrupt inside the CPU invoked. A interrupt handler registered by kernel will transform the signal from DMA into a done callback for write to TCP stream method. Of course, the actual TCP stack is much more complex. These sentences are just idea how the thing works.
For the case read from TCP stream, when a package come in on networking card, there is another interrupt invoked. The another handler registered by kernel will transform the interrupt to event on golang side.
Again, the real case is very very complex. There are many OSes, many versions, many kind of IO operations and many hardware devices.
Upvotes: 2