who(1) diff to show more of hostname

2010-11-09 Thread Otto Moerbeek
Hi,

Make who(1) a tiny bit smarter and show more of the host part. Max
linewidth is 80.

-Otto

Index: who.c
===
RCS file: /cvs/src/usr.bin/who/who.c,v
retrieving revision 1.18
diff -u -p -r1.18 who.c
--- who.c   27 Oct 2009 23:59:50 -  1.18
+++ who.c   10 Nov 2010 07:35:48 -
@@ -59,7 +59,9 @@ int show_labels;  /* show column labels 
 int show_quick;/* quick, names only */
 
 #define NAME_WIDTH 8
-#define HOST_WIDTH 32
+#define HOST_WIDTH 45
+
+int hostwidth = HOST_WIDTH;
 
 int
 main(int argc, char *argv[])
@@ -100,6 +102,11 @@ main(int argc, char *argv[])
if (show_quick) {
only_current_term = show_term = show_idle = show_labels = 0;
}
+   
+   if (show_term)
+   hostwidth -= 2;
+   if (show_idle)
+   hostwidth -= 6;
 
if (show_labels)
output_labels();
@@ -245,7 +252,7 @@ output(struct utmp *up)
}

if (*up->ut_host)
-   printf("  (%.*s)", HOST_WIDTH, up->ut_host);
+   printf("  (%.*s)", hostwidth, up->ut_host);
(void)putchar('\n');
 }
 
@@ -263,7 +270,7 @@ output_labels(void)
if (show_idle)
(void)printf("IDLE  ");
 
-   (void)printf("  %.*s", HOST_WIDTH, "FROM");
+   (void)printf("  %.*s", hostwidth, "FROM");
 
(void)putchar('\n');
 }



Re: SCHED_ASSERT_UNLOCKED is considered harmful in the _kernel_lock()

2010-11-09 Thread Philip Guenther
On Mon, Nov 8, 2010 at 2:59 AM, Mark Kettenis 
wrote:
> If you're considering changing the way we allocate the PCB, we should
> look into moving it off the stack altogether and allocate them from a
> pool.  That would make life simpler on hppa, since pools are mapped
> 1:1 which means issues with non-equivalent aliases go away.

Hmmm.  Since we don't swap out the uspace, is there any reason to not
just make the pcb and pstats part of struct proc?  That gets you your
pool allocation without the overhead of Yet Another Pool.


Philip



Re: amd64 segment cleanup: part 3

2010-11-09 Thread Philip Guenther
On Tue, Nov 9, 2010 at 10:41 AM, Mike Belopuhov  wrote:
> On Sun, Oct 31, 2010 at 17:10 -0700, Philip Guenther wrote:
...
>> The TSS also contains the pointer to the stack used for double faults.
>> Previously, this was placed one page above each process's PCB.  Rather
>> than change that on each context switch, I've just left it set to one page
>> above each CPU's idle process's PCB.
>
> i failed to find the code that does this.  could you please point me to it.
>
> is it supposed to be referenced by the tss_ist[1]?

No, the double-fault stack is tss_ist[0].  That's set in
x86_64_proc0_tss_ldt_init() and x86_64_init_pcb_tss_ldt (primary vs
secondary processor) to point into the processor's idle process
uspace.  It's the same place it points now, it's just that the patch
changes it to only get set once, when each processor's idle process is
created, instead of having it be a per-process value by virtue of the
tss being per-process.


> you might also want to remove disabled amd64_{get,set}_ioperm code.

Good point, though I'm inclined to do that as a separate commit.


>> Index: amd64/locore.S
>> ===
>> RCS file: /cvs/src/sys/arch/amd64/amd64/locore.S,v
>> retrieving revision 1.42
>> diff -u -p -r1.42 locore.S
>> --- amd64/locore.S26 Oct 2010 05:49:10 -  1.42
>> +++ amd64/locore.S31 Oct 2010 23:04:12 -
>> @@ -727,6 +727,7 @@ ENTRY(cpu_switchto)
>>   pushq   %r15
>>
>>   movq%rdi, %r13
>> + movq%rdi, %r15
>
> why do you need to load 'r15' with 'rdi'?
> it looks like a dead store to me

Hmm, yeah, that was a debugging leftover.


>> + /* clear the old pmap's bit for the cpu */
>> + movqPCB_PMAP(%r13),%rcx
>> + lock
>> + btcl%edi,PM_CPUS(%rcx)
>> +
>
> 'btr' looks a bit more explicit to me.  but that's just nitpicking.

Yeah, that's clearer.


>> + /* set the new pmap's bit for the cpu */
>> + movlCPUVAR(CPUID),%edi
>> + movqPCB_PMAP(%r13),%rcx
>> + movlPM_CPUS(%rcx),%eax
>> + movq%rax,%r14
>
> the previous line looks like a dead store to me.

Ah, that was debugging code, capturing rax before the diagnostic check
which overwrites it.  It can go, yes.

(Oooh, two 'movq's that can go!  Time to rerun the perf test!)
(Yes, that's a joke)


>> + lock
>> + btsl%edi,PM_CPUS(%rcx)
>> +#ifdef DIAGNOSTIC
>> + jc  _C_LABEL(switch_pmcpu_set)
>
> that's a nice 'free' check, indeed.

It's kinda unfortunate that the "no longer using this pmap" btcl above
can't do the same thing, but since this code is skipped for kernel
threads, the kernel pmap isn't normally marked as used.  I suppose the
DIAGNOSTIC code could have a check for whether the process being
switched _from_ was a P_SYSTEM process, but it didn't feel worth it at
that point...


>>   /* exceptions */
>>   for (x = 0; x < 32; x++) {
>>   ist = (x == 8) ? 1 : 0;
>> + // ist = (x == 8) ? 1 : (x == 2) ? 2 : 0;
>
> why do you need this comment?  or is it a reminder to have
> a separate stack for the NMI in the future?

Yep.  I was thinking of doing it as part of this diff, realized I
didn't know how to test it, and so left it as a comment.


Philip Guenther



Prevent recursion in acpibat(4)

2010-11-09 Thread Mark Kettenis
As can be seen from PR 6508, the current implementation of the
acpibat(4) notify stuff causes infinite recursion.  The AML for that
particular machine will execute a Notify(\_SC.BAT, 0x81) from the
_BST() method.  Since we always execute both _BST() and _BIF() from
the \_SC.BAT notify handler it's easy to see that things go wrong.
The fix is to only call _BST() if the notify value is 0x80 (or 0x00
for the "poll" case) and only call _BIF() if the notify value is 0x81.

This diff also simplifies the battery presence detect logic, which was
unecessaryly complex.

ok?


Index: acpibat.c
===
RCS file: /cvs/src/sys/dev/acpi/acpibat.c,v
retrieving revision 1.57
diff -u -p -r1.57 acpibat.c
--- acpibat.c   7 Aug 2010 16:55:38 -   1.57
+++ acpibat.c   7 Nov 2010 21:04:36 -
@@ -186,13 +186,6 @@ acpibat_refresh(void *arg)
return;
}
 
-   /*
-* XXX don't really need _BIF but keep it here in case we
-* miss an insertion/removal event
-*/
-   acpibat_getbif(sc);
-   acpibat_getbst(sc);
-
/* _BIF values are static, sensor 0..3 */
if (sc->sc_bif.bif_last_capacity == BIF_UNKNOWN) {
sc->sc_sens[0].value = 0;
@@ -386,7 +379,8 @@ out:
return (rv);
 }
 
-/* XXX it has been observed that some systems do not propagate battery
+/*
+ * XXX it has been observed that some systems do not propagate battery
  * insertion events up to the driver.  What seems to happen is that DSDT
  * does receive an interrupt however the originator bit is not set.
  * This seems to happen when one inserts a 100% full battery.  Removal
@@ -400,23 +394,25 @@ acpibat_notify(struct aml_node *node, in
 {
struct acpibat_softc*sc = arg;
int64_t sta;
-   int present;
 
dnprintf(10, "acpibat_notify: %.2x %s\n", notify_type,
sc->sc_devnode->name);
 
/* Check if installed state of battery has changed */
if (aml_evalinteger(sc->sc_acpi, node, "_STA", 0, NULL, &sta) == 0) {
-   present = sta & STA_BATTERY;
-   if (!sc->sc_bat_present && present)
+   if (sta & STA_BATTERY)
sc->sc_bat_present = 1;
-   else if (sc->sc_bat_present && !present)
+   else
sc->sc_bat_present = 0;
}
+
switch (notify_type) {
+   case 0x00:  /* Poll sensors */
case 0x80:  /* _BST changed */
+   acpibat_getbst(sc);
break;
case 0x81:  /* _BIF changed */
+   acpibat_getbif(sc);
break;
default:
break;



Re: amd64 segment cleanup: part 3

2010-11-09 Thread Mike Belopuhov
On Sun, Oct 31, 2010 at 17:10 -0700, Philip Guenther wrote:
> Okay, enough cleanup; time to simplify the TSS handling by moving from 
> TSS-per-process to TSS-per-CPU.  This eliminates the need to ever change 
> GDT entries after startup and the associated ~4k process limit.
> 
> Where do we place that TSS?  Before, it was part of the PCB; here I've put 
> the primary CPU's TSS between the IDT and the primary CPU's GDT.  For 
> secondary CPU's I place it right after the CPU's GDT. The exact location 
> isn't important, they just need to be in unpageable, unmanaged memory like 
> the GDT, so putting it next to the GDT is convenient.
> 
> With the TSS being per-CPU, we no longer need to change the 'task busy' 
> flag or load the task register when doing a context switch. Instead, we 
> just poke into the TSS the pointer to the process's kernel stack.
> 
> The TSS also contains the pointer to the stack used for double faults.  
> Previously, this was placed one page above each process's PCB.  Rather 
> than change that on each context switch, I've just left it set to one page 
> above each CPU's idle process's PCB.

i failed to find the code that does this.  could you please point me to it.

is it supposed to be referenced by the tss_ist[1]?

>  I think we can reduce the size of 
> normal processes' USPACE by a page, or maybe even two, what with the PCB 
> shrinking, but that can wait.
> 
> To increase speed and paranoia slightly, I've inlined pmap_activate() and 
> pmap_deactivate() into the asm cpu_switchto routine.  That let me add a 
> 'free' check for the new pmap already being marked as active on the CPU; 
> that check earlier caught some sloppy handling of that bitmap.
> 
> Garbage collect the hasn't-been-used-in-years GDT update IPI.
> 
> 
> As before, I would like to hear tests for both real AMD and Intel CPUs; 
> thank you to everyone that sent results before!
> 
> 
> Philip Guenther
> 
> 

you might also want to remove disabled amd64_{get,set}_ioperm code.

some comments inline, otherwise looks good to me.  i'm running it on
my core i5.

> Index: amd64/locore.S
> ===
> RCS file: /cvs/src/sys/arch/amd64/amd64/locore.S,v
> retrieving revision 1.42
> diff -u -p -r1.42 locore.S
> --- amd64/locore.S26 Oct 2010 05:49:10 -  1.42
> +++ amd64/locore.S31 Oct 2010 23:04:12 -
> @@ -727,6 +727,7 @@ ENTRY(cpu_switchto)
>   pushq   %r15
>  
>   movq%rdi, %r13
> + movq%rdi, %r15

why do you need to load 'r15' with 'rdi'?
it looks like a dead store to me

>   movq%rsi, %r12
>  
>  #ifdef DIAGNOSTIC
> @@ -741,6 +742,8 @@ ENTRY(cpu_switchto)
>   movb$SONPROC,P_STAT(%r12)   # p->p_stat = SONPROC
>   SET_CURPROC(%r12,%rcx)
>  
> + movlCPUVAR(CPUID),%edi
> +
>   /* If old proc exited, don't bother. */
>   testq   %r13,%r13
>   jz  switch_exited
> @@ -752,13 +755,16 @@ ENTRY(cpu_switchto)
>*   %rax, %rcx - scratch
>*   %r13 - old proc, then old pcb
>*   %r12 - new proc
> +  *   %edi - cpuid
>*/
>  
> - movq%r13,%rdi
> - callpmap_deactivate
> -
>   movqP_ADDR(%r13),%r13
>  
> + /* clear the old pmap's bit for the cpu */
> + movqPCB_PMAP(%r13),%rcx
> + lock
> + btcl%edi,PM_CPUS(%rcx)
> +

'btr' looks a bit more explicit to me.  but that's just nitpicking.

>   /* Save stack pointers. */
>   movq%rsp,PCB_RSP(%r13)
>   movq%rbp,PCB_RBP(%r13)
> @@ -781,30 +787,29 @@ switch_exited:
>   movqPCB_RSP(%r13),%rsp
>   movqPCB_RBP(%r13),%rbp
>  
> -#if 0
> + movqCPUVAR(TSS),%rcx
> + movqPCB_KSTACK(%r13),%rdx
> + movq%rdx,TSS_RSP0(%rcx)
> +
> + movqPCB_CR3(%r13),%rax
> + movq%rax,%cr3
> +
>   /* Don't bother with the rest if switching to a system process. */
>   testl   $P_SYSTEM,P_FLAG(%r12)
>   jnz switch_restored
> -#endif
>  
> - /* Load TSS info. */
> -#ifdef MULTIPROCESSOR
> - movqCPUVAR(GDT),%rax
> -#else   
> - movq_C_LABEL(gdtstore)(%rip),%rax
> + /* set the new pmap's bit for the cpu */
> + movlCPUVAR(CPUID),%edi
> + movqPCB_PMAP(%r13),%rcx
> + movlPM_CPUS(%rcx),%eax
> + movq%rax,%r14

the previous line looks like a dead store to me.

> + lock
> + btsl%edi,PM_CPUS(%rcx)
> +#ifdef DIAGNOSTIC
> + jc  _C_LABEL(switch_pmcpu_set)

that's a nice 'free' check, indeed.

>  #endif
> - movlP_MD_TSS_SEL(%r12),%edx
> -
> - /* Switch TSS. Reset "task busy" flag before */
> - andl$~0x0200,4(%rax,%rdx, 1)
> - ltr %dx
>  
> - movq%r12,%rdi
> - call_C_LABEL(pmap_activate)
> -
> -#if 0
>  switch_restored:
> -#endif
>   /* Restore cr0 (including FPU state). */
>   movlPCB_CR0(%r13),%ecx
>  #ifdef MULTIPROCESSOR
> Index: amd64/machdep.c
> ===

Re: mmap()'ing non-vnode files

2010-11-09 Thread Mike Belopuhov
On Tue, Nov 9, 2010 at 2:22 PM, Wouter Coene  wrote:
> Hi,
>
> I'm looking into porting Linux's Kernel Virtual Machine (KVM) host to
> OpenBSD. Under Linux, KVM and the user-space virtual machine share a
> datastructure containing the state of the virtual CPU. This structure is
> owned by the kernel, and accessed from userland by mmap()'ing the file
> handle referring to the KVM virtual CPU.
>
> However, the OpenBSD kernel only allows mmap()'ing files that are vnodes. Is
> it worth the trouble to implement the KVM virtual CPU handle as a vnode with
> all the boilerplate that comes with that? Or is there perhaps an easier way
> (preferrably one that doesn't break source-compatibility with Linux's KVM
> too much)?
>
> Thanks in advance for any help,
> Wouter Coene
>
>

you can mmap character devices provided that the driver implements
the interface.



mmap()'ing non-vnode files

2010-11-09 Thread Wouter Coene
Hi,

I'm looking into porting Linux's Kernel Virtual Machine (KVM) host to
OpenBSD. Under Linux, KVM and the user-space virtual machine share a
datastructure containing the state of the virtual CPU. This structure is
owned by the kernel, and accessed from userland by mmap()'ing the file
handle referring to the KVM virtual CPU.

However, the OpenBSD kernel only allows mmap()'ing files that are vnodes. Is
it worth the trouble to implement the KVM virtual CPU handle as a vnode with
all the boilerplate that comes with that? Or is there perhaps an easier way
(preferrably one that doesn't break source-compatibility with Linux's KVM
too much)?

Thanks in advance for any help,
Wouter Coene



Re: waitpid not returning 0 when WNOHANG specified ?

2010-11-09 Thread Christiano F. Haesbaert
On 9 November 2010 06:54, Otto Moerbeek  wrote:
> On Tue, Nov 09, 2010 at 08:17:59AM +0100, Markus Bergkvist wrote:
>
>> On 11/09/10 03:27, Philip Guenther wrote:
>> >On Mon, Nov 8, 2010 at 4:10 PM, Christiano F. Haesbaert
>> >  wrote:
>> >>I must be doing something really silly but it seems waitpid ends up
>> >>returning -1 if WNOHANG is specified and there are no children to
>> >>reap.
>> >
>> >Umm, that's what the standard specifies.
>> >
>> >
>>
>> waitpid(2), RETURN VALUES
>> "Otherwise, if WNOHANG is specified and there are no stopped or
>> exited children, 0 is returned."
>
> And before the "Otherwise", it says:  "If there are no children not
> previously awaited, -1 is returned with errno set to [ECHILD]."
>
> To me this sentence is hard to understand, but I suspect the testcase
> hits this part.
>

Exactly, I got confused on this sentence and assumed the other way.

Sorry for the noise.



amd64: Phenom 9x00's TLB errata warning

2010-11-09 Thread SASANO Takayoshi
Hello,

Phenom 9500 has TLB errata and this should be workarounded by BIOS.
But some BIOS do nothing by default, I think the warning is needed.

Here is the patch, please review.

--
amd64errata.c
- applied following NetBSD's src/sys/arch/x86/x86/errata.c fix
  revision 1.8, 1.13, 1.17 and 1.18

specialreg.h
- add definitions for amd64errata.c
- modified NB_CFG_DISIOREQLOCK and DC_CFG_DIS_CNV_WC_SSO,
  they are misdefined (see src/sys/arch/x86/include/specialreg.h
  of NetBSD, revision 1.48 and 1.49)
-- 
SASANO Takayoshi (JG1UAA/@uaa) [http://www.uaa.org.uk] 

[demime 1.01d removed an attachment of type application/octet-stream]



Re: amd64: Phenom 9x00's TLB errata warning

2010-11-09 Thread SASANO Takayoshi
Oops, try again...

At Tue, 09 Nov 2010 20:48:37 +0900,
SASANO Takayoshi wrote:
> 
> Hello,
> 
> Phenom 9500 has TLB errata and this should be workarounded by BIOS.
> But some BIOS do nothing by default, I think the warning is needed.
> 
> Here is the patch, please review.
> 
> --
> amd64errata.c
>   - applied following NetBSD's src/sys/arch/x86/x86/errata.c fix
> revision 1.8, 1.13, 1.17 and 1.18
> 
> specialreg.h
>   - add definitions for amd64errata.c
>   - modified NB_CFG_DISIOREQLOCK and DC_CFG_DIS_CNV_WC_SSO,
> they are misdefined (see src/sys/arch/x86/include/specialreg.h
> of NetBSD, revision 1.48 and 1.49)
> -- 
> SASANO Takayoshi (JG1UAA/@uaa) [http://www.uaa.org.uk] 
> 
> [demime 1.01d removed an attachment of type application/octet-stream]
> 


Index: arch/amd64/amd64/amd64errata.c
===
RCS file: /cvs/src/sys/arch/amd64/amd64/amd64errata.c,v
retrieving revision 1.2
diff -u -p -r1.2 amd64errata.c
--- arch/amd64/amd64/amd64errata.c  26 Jun 2008 05:42:09 -  1.2
+++ arch/amd64/amd64/amd64errata.c  9 Nov 2010 11:45:32 -
@@ -64,6 +64,7 @@ typedef struct errata {
 typedef enum cpurev {
BH_E4, CH_CG, CH_D0, DH_CG, DH_D0, DH_E3, DH_E6, JH_E1,
JH_E6, SH_B0, SH_B3, SH_C0, SH_CG, SH_D0, SH_E4, SH_E5,
+   DR_BA, DR_B2, DR_B3,
OINK
 } cpurev_t;
 
@@ -78,6 +79,7 @@ static const u_int cpurevs[] = {
SH_CG, 0xf4a, SH_CG, 0xf5a, SH_CG, 0xf7a,
SH_D0, 0x0010f40, SH_D0, 0x0010f50, SH_D0, 0x0010f70,
SH_E4, 0x0020f51, SH_E4, 0x0020f71, SH_E5, 0x0020f42,
+   DR_BA, 0x0100f2a, DR_B2, 0x0100f22, DR_B3, 0x0100f23,
OINK
 };
 
@@ -117,6 +119,14 @@ static const uint8_t amd64_errata_set8[]
SH_D0, SH_D0, SH_D0, SH_E4, SH_E4, SH_E5, OINK
 };
 
+static const uint8_t amd64_errata_set9[] = {
+   DR_BA, DR_B2, OINK
+};
+
+static const uint8_t amd64_errata_set10[] = {
+   DR_BA, DR_B2, DR_B3, OINK
+};
+
 static int amd64_errata_setmsr(struct cpu_info *, errata_t *);
 static int amd64_errata_testmsr(struct cpu_info *, errata_t *);
 
@@ -178,7 +188,6 @@ static errata_t errata[] = {
113, 0, MSR_BU_CFG, amd64_errata_set3,
amd64_errata_setmsr, BU_CFG_WBENHWSBDIS
},
-#ifdef MULTIPROCESSOR
/*
 * 69: Multiprocessor Coherency Problem with Hardware
 * Prefetch Mechanism
@@ -211,7 +220,6 @@ static errata_t errata[] = {
107, 0, MSR_BU_CFG, amd64_errata_set2,
amd64_errata_testmsr, BU_CFG_THRL2IDXCMPDIS
},
-#if 0
/*
 * 122: TLB Flush Filter May Cause Coherency Problem in
 * Multiprocessor Systems
@@ -220,8 +228,41 @@ static errata_t errata[] = {
122, 0, MSR_HWCR, amd64_errata_set4,
amd64_errata_setmsr, HWCR_FFDIS
},
-#endif
-#endif /* MULTIPROCESSOR */
+   /*
+* 254: Internal Resource Livelock Involving Cached TLB Reload
+*/
+   {
+   254, 0, MSR_BU_CFG, amd64_errata_set9,
+   amd64_errata_testmsr, BU_CFG_ERRATA_254
+   },
+   /*
+* 261: Processor May Stall Entering Stop-Grant Due to Pending Data
+* Cache Scrub
+*/
+   {
+   261, 0, MSR_DC_CFG, amd64_errata_set10,
+   amd64_errata_testmsr, DC_CFG_ERRATA_261
+   },
+   /*
+* 298: L2 Eviction May Occur During Processor Operation To Set
+* Accessed or Dirty Bit
+*/
+   {
+   298, 0, MSR_HWCR, amd64_errata_set9,
+   amd64_errata_testmsr, HWCR_TLBCACHEDIS
+   },
+   {
+   298, 0, MSR_BU_CFG, amd64_errata_set9,
+   amd64_errata_testmsr, BU_CFG_ERRATA_298
+   },
+   /*
+* 309: Processor Core May Execute Incorrect Instructions on
+* Concurrent L2 and Northbridge Response
+*/
+   {
+   309, 0, MSR_BU_CFG, amd64_errata_set9,
+   amd64_errata_testmsr, BU_CFG_ERRATA_309
+   },
 };
 
 static int 
Index: arch/amd64/include/specialreg.h
===
RCS file: /cvs/src/sys/arch/amd64/include/specialreg.h,v
retrieving revision 1.19
diff -u -p -r1.19 specialreg.h
--- arch/amd64/include/specialreg.h 29 Apr 2010 17:00:48 -  1.19
+++ arch/amd64/include/specialreg.h 9 Nov 2010 11:45:32 -
@@ -316,11 +316,13 @@
  * These require a 'passcode' for access.  See cpufunc.h.
  */
 #defineMSR_HWCR0xc0010015
+#defineHWCR_TLBCACHEDIS0x0008
 #defineHWCR_FFDIS  0x0040
 
 #defineMSR_NB_CFG  0xc001001f
-#defineNB_CFG_DISIOREQLOCK 0x0004ULL
+#defineNB_CFG_DISIOREQLOCK 0x0008ULL
 #defineNB_CFG_DISDATMSK0x0010ULL
+#defineNB_CFG

Re: waitpid not returning 0 when WNOHANG specified ?

2010-11-09 Thread Otto Moerbeek
On Tue, Nov 09, 2010 at 08:17:59AM +0100, Markus Bergkvist wrote:

> On 11/09/10 03:27, Philip Guenther wrote:
> >On Mon, Nov 8, 2010 at 4:10 PM, Christiano F. Haesbaert
> >  wrote:
> >>I must be doing something really silly but it seems waitpid ends up
> >>returning -1 if WNOHANG is specified and there are no children to
> >>reap.
> >
> >Umm, that's what the standard specifies.
> >
> >
> 
> waitpid(2), RETURN VALUES
> "Otherwise, if WNOHANG is specified and there are no stopped or
> exited children, 0 is returned."

And before the "Otherwise", it says:  "If there are no children not
previously awaited, -1 is returned with errno set to [ECHILD]."

To me this sentence is hard to understand, but I suspect the testcase
hits this part.

-Otto