At 02:25 PM 4/22/2002 -0400, Charles Lane wrote:
>Craig A. Berry writes:
>> At 10:04 AM 4/22/2002 -0400, Charles Lane wrote:

>> >So if we are sucessful in opening a channel to the termination mbx and
>> >grabbing the termination message, we'll mess up whatever code was
>> >waiting for that message.  
>
>> Really?  What prevents two readers from reading the same thing?
>
>Well, whoever reads the message first causes the message to be removed
>from the mailbox.  

If only the $creprc caller can safely read from the termination 
mailbox, then yes, my assumptions in making waitpid do so are off base.  I 
wonder why lib$spawn even bothers with a termination mailbox then.

>> What about putting a timeout on the $qiow that is reading from the 
>> termination mailbox?  If it completes with a timeout, we can requeue it, but 
>> in the meanwhile whatever else was pending should have a chance to fire.

Well, the timeout option only exists for the terminal driver, not the 
mailbox driver, so that suggestion wouldn't have worked anyway.

>Here's a patch that implements my suggested changes to waitpid; give it 
>a shot.  It seems to get us through the pipe torture tests. 

OK, I'll try it.  And just to confuse things, here's an alternate patch.  It 
looked to me like the only time we could fail to recognize a pipe subprocess 
was when my_pclose had already initiated shutdown with either $delprc or 
$forcex.  So, this just checks to see if the process is in one of those 
states and refrains from posting a read to the termination mailbox.  It also 
protects itself from the case of no writer on the mailbox existing.  
test_pipe.pl looks good after this, but if a successful read from the 
mailbox messes up another reader then your patch is probably better.

--- vms/vms.c;-0        Tue Apr  9 14:26:06 2002
+++ vms/vms.c   Mon Apr 22 12:14:09 2002
@@ -2684,13 +2684,17 @@
       $DESCRIPTOR(intdsc,"0 00:00:01");
       unsigned long int ownercode = JPI$_OWNER, ownerpid;
       unsigned long int pidcode = JPI$_PID, mypid;
+#     define PCB$M_DELPEN 0x2  /* delete pending from $PCBDEF macro */
+#     define PCB$M_FORCPEN 0x4  /* forced exit pending from $PCBDEF macro */
+      unsigned long int pcbsts;
       unsigned long int interval[2];
       int termination_mbu = 0;
       unsigned short qio_iosb[4];
       unsigned int jpi_iosb[2];
-      struct itmlst_3 jpilist[3] = { 
+      struct itmlst_3 jpilist[4] = { 
           {sizeof(ownerpid),        JPI$_OWNER, &ownerpid,        0},
           {sizeof(termination_mbu), JPI$_TMBU,  &termination_mbu, 0},
+          {sizeof(pcbsts),          JPI$_STS,   &pcbsts,          0},
           {                      0,         0,                 0, 0} 
       };
       char trmmbx[NAM$C_DVI+1];
@@ -2708,8 +2712,9 @@
       }
 
       /* Get the owner of the child so I can warn if it's not mine, plus
-       * get the termination mailbox.  If the process doesn't exist or I
-       * don't have the privs to look at it, I can go home early.
+       * get the termination mailbox and process control block status.  
+       * If the process doesn't exist or I don't have the privs to look 
+       * at it, I can go home early.
        */
       sts = sys$getjpiw(0,&pid,NULL,&jpilist,&jpi_iosb,NULL,NULL);
       if (sts & 1) sts = jpi_iosb[0];
@@ -2738,8 +2743,13 @@
       }
 
       /* It's possible to have a mailbox unit number but no actual mailbox; we 
-       * check for this by assigning a channel to it, which we need anyway.
+       * check for this by assigning a channel to it, which we need anyway, but
+       * we don't even try that if the process already has a delete or forced
+       * exit pending.
        */
+      if ((pcbsts && PCB$M_DELPEN) || (pcbsts && PCB$M_FORCPEN)) {
+          termination_mbu = 0;
+      }
       if (termination_mbu != 0) {
           sprintf(trmmbx, "MBA%d:", termination_mbu);
           trmmbxdsc.dsc$w_length = strlen(trmmbx);
@@ -2769,7 +2779,7 @@
           sts = SS$_NORMAL;
           while (sts & 1) {
               memset((void *) &trmmsg, 0, sizeof(trmmsg));
-              sts = sys$qiow(0,mbxchan,IO$_READVBLK,&qio_iosb,0,0,
+              sts = sys$qiow(0,mbxchan,IO$_READVBLK|IO$M_WRITERCHECK,&qio_iosb,0,0,
                              &trmmsg,ACC$K_TERMLEN,0,0,0,0);
               if (sts & 1) sts = qio_iosb[0];
 
@@ -2778,10 +2788,13 @@
                    && trmmsg.acc$l_pid == pid ) {
 
                   if (statusp) *statusp = trmmsg.acc$l_finalsts;
-                  sts = sys$dassgn(mbxchan);
                   break;
               }
           }
+
+          if (sts == SS$_NOWRITER) sts = SS$_NORMAL;
+          _ckvmssts(sys$dassgn(mbxchan));
+
       } /* termination_mbu ? */
 
       _ckvmssts(sts);
[end]

Reply via email to