[nanomsg] Re: [Non-DoD Source] Re: nanomsg rewrite - new API

  • From: Michael Powell <mwpowellhtx@xxxxxxxxx>
  • To: "nanomsg@xxxxxxxxxxxxx" <nanomsg@xxxxxxxxxxxxx>
  • Date: Mon, 12 Dec 2016 14:09:38 -0500

On Mon, Dec 12, 2016 at 1:07 PM, Karan, Cem F CIV USARMY RDECOM ARL
(US) <cem.f.karan.civ@xxxxxxxx> wrote:

-----Original Message-----
From: nanomsg-bounce@xxxxxxxxxxxxx [mailto:nanomsg-bounce@xxxxxxxxxxxxx] On
Behalf Of Michael Powell
Sent: Monday, December 12, 2016 11:45 AM
To: nanomsg@xxxxxxxxxxxxx
Subject: [nanomsg] Re: [Non-DoD Source] Re: nanomsg rewrite - new API

On Mon, Dec 12, 2016 at 9:12 AM, Karan, Cem F CIV USARMY RDECOM ARL
(US) <cem.f.karan.civ@xxxxxxxx> wrote:
Hi Garrett, I like what you're trying to do!  Two thoughts:

First, are you making changes to how new transports/protocols are added to
the library?  I'd really like to be able to use what you're
doing on top of my simulator framework, but would need a stable,
well-documented API that operates on UDP-like packets rather than
TCP streams to really use it.

Second, I'm going to make an argument for integers rather than pointers
for socket descriptors.  I ran into some weird ABA-like problems
(https://en.wikipedia.org/wiki/ABA_problem) in some code that I was using at
one point that I only figured out after a month's worth of
work.  The problem was that one thread created a struct, handed it off to a
second thread, and then deleted the struct, leaving the second
thread with a dangling pointer.  However, before the second thread woke up,
the first thread created another struct on the heap of the
same type, which, thanks to the magic of malloc() on that particular
machine, happened to be in exactly the same location as the first
struct.  This only worked on my coworker's machine, where it never crashed.
On any other machine, it crashed.

This DOES NOT sound like a pointers versus FDs issue to me. It sounds more
like threading 101. I would start there IMO.

Agreed, and I mentioned it to my coworker at the time as well.  That along
with 'thou shalt use locks on ALL shared objects no matter what'[1] was
explained at length to him.  The changes I put in were to save MY sanity, not
his.

It sounds suspiciously like a "reference" to scoped memory is being
passed into the thread. Which, of course, will not be there once the
caller/invoker of the thread leaves its scope.

To avoid similar problems in the library, I converted everything to use 32
bit IDs instead.  The library owned all memory it allocated, and
clients could ask about particular information via the 32 bit IDs.  The
trick was the library never reused an ID within the same process; it
just kept incrementing a counter to generate IDs.  If a datastructure was
deallocated, then its ID was purged from the hashmap, and any
requests for it would cause an immediate crash.  The only downside was that
the library had to lookup information within the hashmap
each time, which caused a tiny slowdown, but it was small enough that it
wasn't noticeable in that particular application.

Probably working around buggy code with more buggy code, also IMO.
While I haven't seen your code base, per se, ask me how I know? When you
live with a flawed approach, you end up with a flawed
outcome.
This learned from HARD experience.

Agreed, but this was the easiest way for me to save my sanity.

That's my tax dollars at work!

I'll admit that pointers are MUCH easier to use, but that was my
experience with sharing pointers across an API interface. Inside the
library, we used pointers everywhere, but it was easier to deal with any
headaches from that there.

Thanks, and I'm looking forwards to the rewrite; where are you putting the
code?  I'd like to see it.

Thanks,
Cem Karan

Thanks,
Cem Karan

[1] For some reason, there are still people in the world that think that if an
object is 'small enough', then all reads/writes to it will be atomic, and all
threads will see the same results, even if they are running on different CPUs.
That's when I have to explain memory consistency, barriers, etc. to them.
Some people get it, some don't.  For those that don't, I do stuff like the FD
trick, or worse, UUIDs so that when they decide to serialize out their data,
it will NEVER deserialize as referencing something valid.  I'm aware that this
is bad programming practice, but sometimes you've got to do what you've got to
do.

Other related posts: