![]() |
![]() HP OpenVMS Systemsask the wizard |
![]() |
The Question is: I have a question on how best to use DECthreads and asynchronous I/O on Alpha & 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 & IOSB while (iosb not complete){ // <== 1 pthread_cond_wait // <== 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.
|