August 13
On Wednesday, 13 August 2025 at 09:46:07 UTC, GL wrote:
> On Tuesday, 12 August 2025 at 14:14:04 UTC, Dmitry Olshansky wrote:
>> That would be something I could look into. I think it should be easily fixable. Do you have some examples that fail?
>
> Hello!
> Shure:
>
> import zmqd;
>
>    zmqd.Context context;
>    zmqd.Socket rec;
>
>    context = Context();
>    rec = Socket(context, SocketType.pull);
>
> ----------
>
> Invalid argument (src/poll.cpp:159)
> Error Program exited with code -6

Cool, so it dies on poll. Since poll is intercepted by photon, there is something I failed to account for. Let's see if I can get it fixed.
August 13
On Wednesday, 13 August 2025 at 10:08:17 UTC, Dmitry Olshansky wrote:
> On Wednesday, 13 August 2025 at 09:46:07 UTC, GL wrote:
>> On Tuesday, 12 August 2025 at 14:14:04 UTC, Dmitry Olshansky wrote:
>>> That would be something I could look into. I think it should be easily fixable. Do you have some examples that fail?
>>
>> Hello!
>> Shure:
>>
>> import zmqd;
>>
>>    zmqd.Context context;
>>    zmqd.Socket rec;
>>
>>    context = Context();
>>    rec = Socket(context, SocketType.pull);
>>
>> ----------
>>
>> Invalid argument (src/poll.cpp:159)
>> Error Program exited with code -6

So that was trivial mistake in handling -1 argument to poll.

Some more digging around and I've got the following to work:

import std.stdio;
import zmqd;
import photon;
import core.thread;

void main()
{
	startloop();
	shared bool terminated = false;
	go({
    	//  Socket to talk to clients
		auto responder = Socket(SocketType.rep);
		writeln("Got socket");
		responder.bind("tcp://*:5555");
		writeln("Binded socket");

		while (!terminated) {
			ubyte[10] buffer;
			responder.receive(buffer);
			writefln("Received: \"%s\"", cast(string)buffer);
			Thread.sleep(1.seconds);
			responder.send("World");
		}
	});
	go({
		writeln ("Connecting to hello world server...");
		auto requester = Socket(SocketType.req);
		requester.connect("tcp://localhost:5555");

		foreach (int requestNbr; 0..10)
		{
			ubyte[10] buffer;
			writefln("Sending Hello #%s", requestNbr);
			if (requestNbr == 9) terminated = true;
			requester.send("Hello");
			requester.receive(buffer);
			writefln("Received: %s #%s", cast(string)buffer, requestNbr);
		}
	});
	runFibers();
}

I need to think a little more about it but I would likely ship it in the next release. Soonish :)


August 16
On Wednesday, 13 August 2025 at 13:28:26 UTC, Dmitry Olshansky wrote:

> I need to think a little more about it but I would likely ship it in the next release. Soonish :)

Thank you!
I will wait with great impatience...
August 16
On Saturday, 16 August 2025 at 09:43:02 UTC, GL wrote:
> On Wednesday, 13 August 2025 at 13:28:26 UTC, Dmitry Olshansky wrote:
>
>> I need to think a little more about it but I would likely ship it in the next release. Soonish :)
>
> Thank you!
> I will wait with great impatience...

With new version v0.12.2 basic ZeroMQd example runs fine. Of other things HTTP server finally scales very well up to 48 cores and is faster than anything I've tried. (see photon-http 0.5.4)

https://github.com/DmitryOlshansky/photon/blob/master/tests/zmq.d

https://code.dlang.org/packages/photon

https://code.dlang.org/packages/photon-http

If you have more ZeroMQ code to test I'd gladly do it.

August 18
On Saturday, 16 August 2025 at 14:51:45 UTC, Dmitry Olshansky wrote:
> On Saturday, 16 August 2025 at 09:43:02 UTC, GL wrote:
>> On Wednesday, 13 August 2025 at 13:28:26 UTC, Dmitry Olshansky wrote:
>>
>>> I need to think a little more about it but I would likely ship it in the next release. Soonish :)
>>
>> Thank you!
>> I will wait with great impatience...
>
> With new version v0.12.2 basic ZeroMQd example runs fine. Of other things HTTP server finally scales very well up to 48 cores and is faster than anything I've tried. (see photon-http 0.5.4)

Actually that should be 0.5.5 :)

And v0.13.0 brings new feature - offload to run compute intensive tasks outside of scheduler. Certain syscalls are automatically routed through it to avoid blocking fibers such as file I/O. Here is simple example using goOnSameThread to make sure we are actually sharing just a single eventloop thread out of many and yet it doesn't block.

import photon;

double gauss(double a, double b, double function(double) f, double step) {
    double sum = 0.0;
    for (double x = a; x < b; x += step) {
        sum += (f(x+step) + f(x))/2 * step;
    }
    return sum;
}

void boom() {
    throw new Exception("Boom!");
}

long fib(long n) {
    if (n <= 2) return 1;
    else {
        return offload(() => fib(n-1)) + offload(() => fib(n-2));
    }
}

void main() {
    startloop();
    go({
        goOnSameThread({
            writeln("Blocking computation");
            writeln("Integral:", gauss(0.0, 10.0, x => x*x, 1e-7));
        });
        goOnSameThread({
            writeln("Blocking computation");
            writeln("Integral:", gauss(0.0, 10.0, x => x*x, 1e-7));
        });
        goOnSameThread({
            writeln("Nonblocking computation");
            writeln("Integral: ", offload(() => gauss(0.0, 10.0, x => x*x, 1e-7)));
        });
        goOnSameThread({
            writeln("Nonblocking computation");
            writeln("Integral: ", offload(() => gauss(0.0, 10.0, x => x*x, 1e-7)));
        });
        goOnSameThread({
            writeln("Catching exception from offloaded computation");
            try {
                offload(&boom);
                assert(0);
            } catch(Exception e) {
                assert(e.msg == "Boom!");
            }
        });
        goOnSameThread({
            writeln("Recursive offload");
            writeln("Fib(15):", offload(() => fib(15)));
        });
    });
    runFibers();
}

Other photon examples:
https://github.com/DmitryOlshansky/photon/tree/master



August 31
On Monday, 18 August 2025 at 15:20:14 UTC, Dmitry Olshansky wrote:
> On Saturday, 16 August 2025 at 14:51:45 UTC, Dmitry Olshansky wrote:
>> [...]
>
> Actually that should be 0.5.5 :)
>
> And v0.13.0 brings new feature - offload to run compute intensive tasks outside of scheduler. Certain syscalls are automatically routed through it to avoid blocking fibers such as file I/O. Here is simple example using goOnSameThread to make sure we are actually sharing just a single eventloop thread out of many and yet it doesn't block.
>
> import photon;
>
> double gauss(double a, double b, double function(double) f, double step) {
>     double sum = 0.0;
>     for (double x = a; x < b; x += step) {
>         sum += (f(x+step) + f(x))/2 * step;
>     }
>     return sum;
> }
>
> void boom() {
>     throw new Exception("Boom!");
> }
>
> long fib(long n) {
>     if (n <= 2) return 1;
>     else {
>         return offload(() => fib(n-1)) + offload(() => fib(n-2));
>     }
> }
>
> void main() {
>     startloop();
>     go({
>         goOnSameThread({
>             writeln("Blocking computation");
>             writeln("Integral:", gauss(0.0, 10.0, x => x*x, 1e-7));
>         });
>         goOnSameThread({
>             writeln("Blocking computation");
>             writeln("Integral:", gauss(0.0, 10.0, x => x*x, 1e-7));
>         });
>         goOnSameThread({
>             writeln("Nonblocking computation");
>             writeln("Integral: ", offload(() => gauss(0.0, 10.0, x => x*x, 1e-7)));
>         });
>         goOnSameThread({
>             writeln("Nonblocking computation");
>             writeln("Integral: ", offload(() => gauss(0.0, 10.0, x => x*x, 1e-7)));
>         });
>         goOnSameThread({
>             writeln("Catching exception from offloaded computation");
>             try {
>                 offload(&boom);
>                 assert(0);
>             } catch(Exception e) {
>                 assert(e.msg == "Boom!");
>             }
>         });
>         goOnSameThread({
>             writeln("Recursive offload");
>             writeln("Fib(15):", offload(() => fib(15)));
>         });
>     });
>     runFibers();
> }
>
> Other photon examples:
> https://github.com/DmitryOlshansky/photon/tree/master

I tried to include all the sources of photon in a application that it's cross-compiled to linux (Pi5, AArch64) and cross-linked with some C libs, and I'm seeing this:

```
2025-08-31T16:22:18.438 [error] extern(C) private ssize_t close(int fd) nothrow
src/photon/linux/core.d(1150,27):        Previous IR type: i32 (i32)
src/photon/linux/core.d(1150,27):        New IR type:      i64 (i32)
```

In linux.core.d: extern(C) private ssize_t close(int fd) nothrow

but `man 2 close` is `int close(int fd)`, it's a bug?





September 01

On Monday, 18 August 2025 at 15:20:14 UTC, Dmitry Olshansky wrote:

>
void main() {
    startloop();
    go({
        goOnSameThread({
            writeln("Blocking computation");
            writeln("Integral:", gauss(0.0, 10.0, x => x*x, 1e-7));
        });
    });
    runFibers();
}

One thing that I think could really be improved about Photon is these funny symbol names.

  • startloop is all-lowercase. It's two words so shouldn't it be startLoop?
  • go doesn't actually do any 'go-ing' right away, since fibres are deferred; so it's a little misleading. Maybe it could be more like schedule?
  • goOnSameThread is hyper-explicit compared to go, but its name still didn't help me understand it until I read the docs. Perhaps goSync or scheduleSync would be more intuitive?
  • runFiber is an unfortunate victim of the American-English disease. It would be nice to have an alias for 'fibre', which is the spelling used in the rest of the English-speaking world.

Would also be great to have a function named something like 'end loop' that cleans up everything that the library uses internally and allows Photon to be freshly re-initialised with startloop again later. This would be essential to using Photon in a modular environment. If Photon is no longer needed, then we don't want it hogging resources until the process dies. Obviously calling such a function should not work within a fibre.

September 03
On Sunday, 31 August 2025 at 14:38:27 UTC, Paolo Invernizzi wrote:
> On Monday, 18 August 2025 at 15:20:14 UTC, Dmitry Olshansky wrote:
>> [...]
>
> I tried to include all the sources of photon in a application that it's cross-compiled to linux (Pi5, AArch64) and cross-linked with some C libs, and I'm seeing this:
>
> ```
> 2025-08-31T16:22:18.438 [error] extern(C) private ssize_t close(int fd) nothrow
> src/photon/linux/core.d(1150,27):        Previous IR type: i32 (i32)
> src/photon/linux/core.d(1150,27):        New IR type:      i64 (i32)
> ```
>
> In linux.core.d: extern(C) private ssize_t close(int fd) nothrow
>
> but `man 2 close` is `int close(int fd)`, it's a bug?

Yeah it's a bug. I think I've hit it recently and fixed. If I fail to produce the next big release in timely manner I'd do a hot fix. You might as well add it to issues on Github so we do not miss it.

September 03

On Monday, 1 September 2025 at 10:22:03 UTC, IchorDev wrote:

>

On Monday, 18 August 2025 at 15:20:14 UTC, Dmitry Olshansky wrote:

>
void main() {
    startloop();
    go({
        goOnSameThread({
            writeln("Blocking computation");
            writeln("Integral:", gauss(0.0, 10.0, x => x*x, 1e-7));
        });
    });
    runFibers();
}

One thing that I think could really be improved about Photon is these funny symbol names.

The fact those symbols even exist in the first place is because the
initial plan was to wrap the D runtime entry point into the following:

startloop();
go({
    Dmain(argc, argv);
});
runFibers();

But convincing people to try use custom druntime is perishable.

Technically this could still be achieved without hacking Druntime a-la:

void main() {
    runPhoton({
       go({...});
    });

with runPhoton doing setup and tear down before running the closure as the first fiber.

>
  • startloop is all-lowercase. It's two words so shouldn't it be startLoop?

It used to start eventloop, now it doesn't so I'd scrap the name altogether.

>
  • go doesn't actually do any 'go-ing' right away, since fibres are deferred; so it's a little misleading. Maybe it could be more like schedule?

It actually does going right away it's just that "root" fibers wait until we start the scheduler. All subsequent fibers are run exactly in the style of Go lang.

>
  • goOnSameThread is hyper-explicit compared to go, but its name still didn't help me understand it until I read the docs. Perhaps goSync or scheduleSync would be more intuitive?

Sync what? :) It's a horrible functionality and has a horrible name to fit.
go starts fiber on some core, goOnSameThread runs on the same core that it's called from.

>
  • runFiber is an unfortunate victim of the American-English disease. It would be nice to have an alias for 'fibre', which is the spelling used in the rest of the English-speaking world.

Aliases are just more cognitive load for everybody. runScheduler might be better.

>

Would also be great to have a function named something like 'end loop' that cleans up everything that the library uses internally and allows Photon to be freshly re-initialised with startloop again later. This would be essential to using Photon in a modular environment. If Photon is no longer needed, then we don't want it hogging resources until the process dies. Obviously calling such a function should not work within a fibre.

Mostly in unittests. It's something I've been looking into but for now I've made startloop idempotent on reinitialization. The fact that photon is tied to globals such as file descriptors and syscalls on these makes it somewhat less amenable to deinitialize.

September 04
On Sunday, 31 August 2025 at 14:38:27 UTC, Paolo Invernizzi wrote:
> On Monday, 18 August 2025 at 15:20:14 UTC, Dmitry Olshansky
[snip]
>> Other photon examples:
>> https://github.com/DmitryOlshansky/photon/tree/master
>
> I tried to include all the sources of photon in a application that it's cross-compiled to linux (Pi5, AArch64) and cross-linked with some C libs, and I'm seeing this:
>
> ```
> 2025-08-31T16:22:18.438 [error] extern(C) private ssize_t close(int fd) nothrow
> src/photon/linux/core.d(1150,27):        Previous IR type: i32 (i32)
> src/photon/linux/core.d(1150,27):        New IR type:      i64 (i32)
> ```
>
> In linux.core.d: extern(C) private ssize_t close(int fd) nothrow
>
> but `man 2 close` is `int close(int fd)`, it's a bug?

Fixed among a ton of other things in v0.14.1.

Introduced Mutex and RecursiveMutex for my upcoming plan to rewrite vibe-core on top of photon. Next in line CondVar and with that I should be ready to reimplement most of vibe.core.sync.

Also notably I ditched timer based sleeps in favor of a scheduler with Mecca's time queue maintained explicitly. Simplified a lot of things. I'm uncertain what I'd do about timers so far their only API was basically sleep which is already handled by delay. That and the coming support for timeout in the select API.

For now it's only Linux and MacOS that have this new scheduler, Windows staying mostly as is until around October when I'd finally get to my Windows desktop.