September 14, 2021
On Tuesday, 14 September 2021 at 12:42:51 UTC, eugene wrote:
> I understand your idea, but even if this will help, the question
> remains - why that particular object is so special for GC.

I had a problem just like this before because I was sending objects through the pipe. And while they were in the pipe - after send but before receive on the other side - it was liable to be collected.

idk your code though if you have a separate reference to the object you should be ok.

but here's the comment from my code when i broke it

https://github.com/adamdruppe/arsd/blob/master/eventloop.d#L180
September 14, 2021

On Tuesday, 14 September 2021 at 12:53:27 UTC, Adam D Ruppe wrote:

>

I had a problem just like this before because I was sending objects through the pipe.

This reminds my (not very successfull) attempts to implement the idea in Rust:

pub struct Edsm {
    name: String,
    pub states: Vec<State>,
    current: usize,
    //    pub state : *mut State, (?)
    pub data: *const void, // long live void* !!!
    //    pub buddy : &'a Edsm, // ... and a hell begins...
    mb: Option<Box<EventSource>>,
    /* self-pipe write end fd, for sending internal events to this machine */
    mxfd: i32,

    io: Option<Box<EventSource>>,
    pub tm: Vec<EventSource>,
    sg: Vec<EventSource>,
    //    pub fs : Option<Box<EventSource>>,
    //    pub ecap : &'a mut Ecap, // Welcome to <'x> HELL again!!!
    ecap: *mut Ecap,
    running: bool, /* self.run() has been invoked */
}

When something (a struct, for ex.) goes to a queue (DList for ex.),
it is out of ANY scope and clever things like borrow checker
can not analyze it's lifetime, oops...

September 14, 2021

On Tuesday, 14 September 2021 at 12:53:27 UTC, Adam D Ruppe wrote:

>

I had a problem just like this before because I was sending objects through the pipe. And while they were in the pipe -

    pub fn msg(&self, code: u32) {
        let ptr: *const u32 = &code;
        let n = unsafe { write(self.mxfd, ptr as *const void, 4) };
        if -1 == n {
            panic!("write({}): {:?}", self.mxfd, Error::last_os_error());
        }
    }

I failed to implement message queue as a wrapper over double list,
rust borrow checker has beaten me :)

September 14, 2021

On Tuesday, 14 September 2021 at 12:52:44 UTC, Steven Schveighoffer wrote:

>

But I agree that a superficial reading of your code seems like it ought to not be collected, and that problem is also worth figuring out. I have high confidence that it's probably not a design flaw in the GC, but rather some misunderstanding of GC-allocated lifetimes in your code. But that doesn't mean it's not actually a bug somewhere in D.

run the server (do not run client):

'LISTENER @ INIT' got 'M0' from 'SELF'
'LISTENER' registered 104 (esrc.TCPListener)
'LISTENER' enabled 104 (esrc.TCPListener)
'LISTENER' enabled 105 (esrc.Signal)
'LISTENER' enabled 106 (esrc.Signal)

wait > 6 seconds
press ^C

observe

___!!!___edsm.StageMachine.~this(): WORKER-95 destroyed...
___!!!___edsm.StageMachine.~this(): WORKER-96 destroyed...
___!!!___edsm.StageMachine.~this(): LISTENER destroyed...

run client (do not run the server)

observe

'CLIENT-9 @ CONN' got 'M2' from 'TX-1'
CLIENT-9:client.EchoClient.clientConnM2() : connection to 'localhost:1111' failed error111)
CLIENT-9:client.EchoClient.clientConnM2() : connection to 'localhost:1111' failed(Connection refused)

press ^C

observe

___!!!___edsm.StageMachine.~this(): STOPPER destroyed...

run server again
run client like this:

./echo-client | grep owner

wait >6.seconds

see

!!! esrc.EventSource.~this() : esrc.Signal (owner STOPPER, fd = 24) this @ 0x7fa6cf12cf60
!!! esrc.EventSource.~this() : esrc.Signal (owner STOPPER, fd = 25) this @ 0x7fa6cf12cf90

WHY this is not happening with echo-server???

September 14, 2021

On Tuesday, 14 September 2021 at 12:09:03 UTC, Steven Schveighoffer wrote:

>

This project is too big and complex

Really, "too big and complex"?
It's as simple as a tabouret :)
It's just a toy/hobby 'project'.

September 14, 2021

On Tuesday, 14 September 2021 at 14:40:55 UTC, eugene wrote:

>

On Tuesday, 14 September 2021 at 12:09:03 UTC, Steven Schveighoffer wrote:

>

This project is too big and complex

Really, "too big and complex"?
It's as simple as a tabouret :)
It's just a toy/hobby 'project'.

A 5-pound phone isn't "too heavy" for an adult to carry but it won't sell well. It's not just about capabilities but what efforts people are willing to expend.

I would troubleshoot your issue by gradually making it @safe and thinking about exceptions. One exception I didn't think about earlier was the 'misaligned pointer' one that I said I suppressed just to find the next @safe complaint:

https://dlang.org/spec/garbage.html says:

>

Do not misalign pointers if those pointers may point into the GC heap,

So even if the lifetimes of your EventSource structs are fixed, the GC can reap the object they're pointing to. You could fix this by having a 128-bit struct and passing C an index into it, so to speak.

September 14, 2021

On Tuesday, 14 September 2021 at 12:09:03 UTC, Steven Schveighoffer wrote:

>

This project is too big and complex for me to diagnose by just reading, it would take some effort

take a look at

https://www.routledge.com/Modeling-Software-with-Finite-State-Machines-A-Practical-Approach/Wagner-Schmuki-Wagner-Wolstenholme/p/book/9780367390860#

'Event/Message Driven State Machines'
(http://zed.karelia.ru/mmedia/bin/edsm-g2-rev-h.tar.gz)
was inspired by this nice book.

September 14, 2021

On Tuesday, 14 September 2021 at 14:56:00 UTC, jfondren wrote:

>

You could fix this by having a 128-bit struct and passing C an index into it

It is another "not so funny joke", isn't it?
Look

    typedef union epoll_data {
        void *ptr;
        int fd;
        uint32_t u32;
        uint64_t u64;
    } epoll_data_t;

    struct epoll_event {
        uint32_t events;      /* Epoll events */
        epoll_data_t data;    /* User data variable */
    } __EPOLL_PACKED;

   // inside the system
   struct epoll_event {
         __u32 events;
         __u64 data;
   } EPOLL_PACKED;

and notice

align (1) struct EpollEvent {
    align(1):
    uint event_mask;
    EventSource es;
    /* just do not want to use that union, epoll_data_t */
}
static assert(EpollEvent.sizeof == 12);
September 14, 2021

On 9/14/21 10:56 AM, jfondren wrote:

>

On Tuesday, 14 September 2021 at 14:40:55 UTC, eugene wrote:

>

On Tuesday, 14 September 2021 at 12:09:03 UTC, Steven Schveighoffer wrote:

>

This project is too big and complex

Really, "too big and complex"?
It's as simple as a tabouret :)
It's just a toy/hobby 'project'.

A 5-pound phone isn't "too heavy" for an adult to carry but it won't sell well. It's not just about capabilities but what efforts people are willing to expend.

I would troubleshoot your issue by gradually making it @safe and thinking about exceptions. One exception I didn't think about earlier was the 'misaligned pointer' one that I said I suppressed just to find the next @safe complaint:

https://dlang.org/spec/garbage.html says:

>

Do not misalign pointers if those pointers may point into the GC heap,

So even if the lifetimes of your EventSource structs are fixed, the GC can reap the object they're pointing to. You could fix this by having a 128-bit struct and passing C an index into it, so to speak.

I don't think this is the problem.

The misaligned pointers are only happening within the stack frame, along with references to the objects stored also in another parameter. So they should not cause problems with the GC.

The storage of the references inside other objects is not misaligned.

-Steve

September 14, 2021

On Tuesday, 14 September 2021 at 15:37:27 UTC, eugene wrote:

>

On Tuesday, 14 September 2021 at 14:56:00 UTC, jfondren wrote:

>

You could fix this by having a 128-bit struct and passing C an index into it

It is another "not so funny joke", isn't it?

No. And when was the first one?

>
align (1) struct EpollEvent {
    align(1):
    uint event_mask;
    EventSource es;
    /* just do not want to use that union, epoll_data_t */
}
static assert(EpollEvent.sizeof == 12);

That's 96 bits. Add 32.

class EventSource { }
align(1) struct EpollEvent {
    align(1):
    uint event_mask;
    EventSource es;
}
struct OuterEpollEvent {
    int _dummy;
    uint event_mask;
    EventSource es;
}
EpollEvent* epollEvent(return ref OuterEpollEvent ev) @trusted {
    return cast(EpollEvent*) &ev.event_mask;
}
void dumpEpollEvent(EpollEvent* ev) @trusted {
    import std.stdio : writeln;

    writeln(*ev);
}

unittest {
    // can't be @safe:
    // Error: field `EpollEvent.es` cannot modify misaligned pointers in `@safe` code
    EpollEvent ev;
    ev.es = new EventSource; // misaligned
}

@safe unittest { // this is fine
    OuterEpollEvent ev;
    ev.event_mask = 0;
    ev.es = new EventSource; // not misaligned
    ev.epollEvent.dumpEpollEvent;
}