  DECthreads, ASTs, and asynchronous I/O? 
 The Question is:
 
I have a question on how best to use DECthreads and asynchronous I/O on
Alpha &amp; VAX 6.2, 7.1, 7.2 and future.
 
In my application I would like to have some threads listening on sockets and
adding the messages they receive to a queue from which a worker thread takes
the messages. Some messages are treated as out-of-band and jump the queue so
I would like the listene
r threads to be executed at a higher priority with Round-Robin scheduling.
 
On systems supporting kernel threads this is easily done using QIOW from the
listener threads. However, I also need to support VAX,
Alpha 6.2, and allow for users who may have set the MULTITHREAD sysgen
parameter to 0.
 
If I do a QIOW in these cases, as I understand things, each time the
listener thread gets its quantum it will process block. Since real-time
scheduling is in use it will never let the worker in.
 
I can do:
 
lock a mutex
QIO with AST &amp; IOSB
while (iosb not complete){  // &lt;== 1
     pthread_cond_wait      // &lt;== 2
 
unlock mutex
 
and in AST do
pthread_cond_signal_int_np
 
However, avoiding a race condition between 1 and 2 depends upon the
condition variable remembering the signal. For pthread_cond_signal the
documentation is clear that there is no memory. For
pthread_cond_signal_int_np it is silent. Does it have memory? If
 it does is that supported behaviour? Is there a better way to support
asynchronous I/o and threads without upcalls enabled?
 
Given I need the AST based code for systems without upcalls is there any
advantage in writing the code to select between the two mechanisms based on
the availability and value of the MULTITHREAD info from GETJPI?
 
The documentation on pthread_cond_signal_int_np says that "A thread resumes
execution at some time after the interrupt handler routine returns". Does
this mean that even though the awakened thread is real-time and higher
priority some other threads may ru
n for a while?
 
Thank-you
 
Martin Kirby
 
 
 The Answer is:
 
  The OpenVMS Wizard is impressed with your grasp of the issues.
 
  If you indeed have a requirement to support common code on V6.2 and
  forward, then your options are limited.  You cannot use $QIOW, because,
  as you observe, if the listener is higher priority with a real-time
  scheduling policy, the worker thread will indeed never run.  However,
  as you surmise, pthread_cond_signal_int_np does indeed have "memory"
  as you suggest, specifically to close the race condition which you
  present.  That function, if there is no current waiter, posts a "pending
  wake-up" on the condition variable, such that the next waiter returns
  immediately instead of waiting, thus preventing a race.
 
  However, as you correctly gleaned from the documentation, a call to
  pthread_cond_signal_int_np may not take effect immediately, and as such
  would probably not suit your needs.  Instead, there is another function
  that you can use which has similar charateristics in terms of the
  "pending wake-up", but which issues the signal immediately.  However,
  there are some restrictions placed on this function of which you need
  to be aware.
 
  The function is called pthread_cond_sig_preempt_int_np.  It is fully
  supported, even if it's not widely documented.  (Look for it in your
  pthread.h; it has proved problemmatical to get it into the manual.)
  It is specifically intended to allow an AST routine to cause the
  currently executing thread to be preempted by a condition variable
  waiter if the waiter has a higher priority and a preemptive scheduling
  policy.
 
  The restriction is that when control returns from this routine to its
  caller, the caller/process/thread/etc. may not be "at AST level" any
  more.  Thus, once this routine returns, you cannot make any further
  assumptions about the atomicity or exclusivity of the execution of
  your AST service routine -- that is, execution of your AST service
  routine may be subject to interruption by a subsequent AST at any
  point.  This is because, during the call to
  pthread_cond_sig_preempt_int_np, a preemption may have occurred,
  resulting in an indeterminent amount of time passing; it would be
  inconvenient, to put it mildly, to have the process running "at AST
  level" this whole time, especially as the code being run is unlikely
  to expect to be running "at AST level".  Thus, if a preemption occurs,
  the process will "dismiss" the AST(ness).  However, there are weird
  cases where the ASTness can be restored during the context switch back
  to the caller of pthread_cond_sig_preempt_int_np.  So, when control
  returns from the function, it's completely unpredictable whether it
  will or won't be "at AST level".  Therefore, the practical suggestion
  is, make the call to pthread_cond_sig_preempt_int_np be the last (or
  only) activity in your AST service routine.  (You begin to see now why
  we are having some trouble documenting this?  :-)
 
  If you are willing to have conditional code in this area, the OpenVMS
  Wizard heartily recommends having alternate code depending on whether
  upcalls are enabled or not.  With upcalls enabled, AST delivery is a
  bit of a performance sink (owing to various compatibility constraints)
  and is best avoided.  Thus, your code could issue the $QIOW, omitting
  the completion AST if upcalls are enabled; then if upcalls are enabled
  call $SYNC and otherwise enter the condition variable wait loop.
 
  Howveer, there is an issue here.  If your code comprises an executable
  image (as opposed to a shareable image), then you will have some
  difficulties enabling upcalls in your case, since that is typically
  done via a qualifier to the LINK command, and that qualifier is not
  available prior to V7.1. Thus, if you link your code on V6.2 you cannot
  enable upcalls; on the other hand, if you link your code on V7.1, running
  it on V6.2 would be unsupported.  So, if you're serious about using
  upcalls, you need to consider shipping two executables.  (There -is- a
  tool which will enable upcalls for an image after it's linked, but the
  tool is not available on V6.2, and the OpenVMS Wizard will not comment
  on whether you can use the tool on V7.1 to set the bit in an image
  linked on V6.2 and then run that image on V6.2.)
 
  The situation gets worse if your code comprises a shareable image. The
  problem is that merely the value of the MULTITHREAD SYSGEN parameter is
  not sufficient to determine whether upcalls are enabled, since this is
  also controlled by how the executable image was linked.  And, unfortunately,
  the OpenVMS Wizard knows of no (documented) interface which code can use
  at run-time to determine whether upcalls are enabled.
 
