tech-userlevel archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

Re: in which we present an ugly hack to make sys/queue.h CIRCLEQ work



The standard committee situation is terribly frustrating in that
things which worked fine on computers which were slower than
todays coffee machines and even existed before i was born get
out-stamped and "improved" for dubious value, e.g. Unix and its
fork(2) and posix_spawn(), and i don't think its funny if
a standard group states

  in the process of relaxing the restrictions on asynchronous
  signal handlers to allow use of atomics, we inadvertently made
  it impossible to use even local variables of non-volatile,
  non-atomic type

 |automatic storage duration going out of scope also counts.  And there
 |are some exceptions for unions (loosely put, the imprinted type can be
 |changed by using a different member of the union).  And there's the
 |"character type" escape....

 |I'm not sure, since storing through one union member and fetching
 |through another brings back issues.  I'd need to see details to do more
 |than take guesses, though, of course.

I think i've recalled a QT blog ([1], mentioned by me 14 months
ago on a FreeBSD list in equal context) falsely.
Regarding queue.3, however, there is not bit-fiddling with values,
it's just comparison and assigning, which makes me wonder why the
union approach shouldn't work for real.
But maybe in the end it'll be just one more matter of intelligent
compiler overoptimization unless it causes problems, and then the
problem occurs again.

  [1] 
<http://blog.qt.digia.com/blog/2011/06/10/type-punning-and-strict-aliasing/>

It's no fun at all, i too had written code like

          // (shares bit space with ConnType)
          pri enum Flags {
                  f_tmask         = 3,
                  f_dipe          = 1<<2, // disconnect pending (no more 
calling)
                  f_mask          = 7
          };

          pri
          mutable Conn    *m_slots;

          pro _Sender(void)
          :
                  m_slots(NIL)
          {}
  [..]
  _pri boolean _Sender::_Disconnect(
          Conn            *_c) const
  {
          RealConn        x, rc;
          _Nydin;

          // try to find an equal (aka the very) connection
          for(x.c=_c, rc.c=m_slots;  (rc.asint &= ~f_mask);  rc.c=rc.c->right) {
                  switch(ConnType(rc.c->flags & f_tmask)) {
                  case ct_ptf_o:
                          if(rc.cfo->obj != x.cfo->obj)
                                  break;
                          // fall..
                  case ct_ptf:
                          if(rc.cf->slot != x.cf->slot)
                                  break;
                          goto jfree;
                  case ct_ptm:
                          if(rc.cml->elobj != x.cml->elobj)
                                  break;
                          if(rc.cml->slot != x.cml->slot)
                                  break;
                          goto jfree;
                  case ct_ptm_t:

To me this makes perfect sense.

--steffen
--- Begin Message ---
> Note that the bog-standard (struct sockaddr *) cast that one needs
> and conventionally uses to call bind(2), connect(2), accept(2), and
> similar is, strictly speaking, illegal.

I don't think so.  The aliasing rules don't say anything about the
types used when passing around pointers to an object, only about the
types used when actually accessing it.  Since the accesses implicit in
calls such as bind() are outside the scope of the abstract C machine, I
don't think there are any nasal demons there.  (Library routines like
getnameinfo, on the other hand, probably cannot be implemented without
either breaking the aliasing rules or assuming implementation-specific
things about how the structs are laid out in array-of-character terms.
To be type-correct, the various structs sockaddr_* really need to be a
single discriminated union...and I'm not sure sockaddr_un can ever be
done type-correctly; I'd have to think about it more.)

> The idea in C is that when you first access fresh memory, that
> imprints it with a type.  You're then supposed to use only the same
> type to access it again later, until you free() it.

Well, not necessarily free(); the freeing implicit in a variable of
automatic storage duration going out of scope also counts.  And there
are some exceptions for unions (loosely put, the imprinted type can be
changed by using a different member of the union).  And there's the
"character type" escape....

>> So if TAILQ_HEAD and TAILQ_ENTRY were the same structure, it
>> wouldn't be an issue.  It doesn't quite leap out to me how that
>> would be possible without changing the API a bit.
> I think it can be done by sticking an anonymous union into
> TAILQ_HEAD,

I'm not sure, since storing through one union member and fetching
through another brings back issues.  I'd need to see details to do more
than take guesses, though, of course.

> but of course anonymous unions aren't supported until C11.

Or gcc; I think gcc had anonymous unions before C11, didn't it?

/~\ The ASCII                             Mouse
\ / Ribbon Campaign
 X  Against HTML                mouse%rodents-montreal.org@localhost
/ \ Email!           7D C8 61 52 5D E7 2D 39  4E F1 31 3E E8 B3 27 4B


--- End Message ---


Home | Main Index | Thread Index | Old Index