On Sat, Nov 22, 2025, at 14:55, Edmond Dantes wrote:
> > So I guess you want to use spawn() in a similar way as call_user_func()
> > works.
> yes
>
> > This changes the behavior of file_get_contents() from the outside
> No.
>
> ```php
> function file_get_contents(string $filename): string
> {
> $fh = fopen();
>
> // It creates an EPOLL event so it can wake us when the data
> becomes available.
> $event = ReactorAPI.create_event_from($fh);
> $waker = Scheduler.getCurrentWaker();
> // Event Driven logic inside.
> $waker.add_event($event, function() use($waker) {
> // Wakeup this coroutine
> $waker.wake();
> });
>
> // suspend current coroutine
> // zz..... z.....
> Scheduler.suspend();
>
> // Continue here after the IO event
>
> // Now we have date, return
> return fread($fh, ....);
> }
> ```
>
> This is pseudocode. You can assume it always works.
> If you call `file_get_contents` directly, it behaves the same way.
> So it does not matter where `file_get_contents` is called.
> Since all PHP code together with TrueAsync runs inside coroutines,
> `file_get_contents` will suspend the coroutine in which it was invoked.
>
> When you call `spawn`, you simply run the function in another
> coroutine, not in your own. But `spawn` has no effect on
> `file_get_contents`.
>
> We’re not at risk of DataRace yet :) We don’t have multithreading.
> And most likely it won’t appear anytime soon.
>
We are in data-race territory though:
spawn(fn() => file_put_contents('file', 'long string'))
spawn(fn() => file_get_contents('file'))
I’m on a phone, so I’m not sure I got all the syntax right, but hopefully my
intent is clear. But if these run “concurrently” the scheduler will
theoretically batch the reading/writing of bytes in an interleaved way, causing
absolute chaos and corruption.
The same thing would happen with db drivers that typically use a token to keep
track of which response goes to which request (I maintain an async db driver
for amphp). There will be a need to ensure the stream cannot be interleaved
with other coroutines. I can do this with amphp locks, but there isn’t even a
semaphore implementation to build a lock around.
— Rob