Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 1 Apr 2009 09:36:09 -0700
From:      "Matthew Fleming" <matthew.fleming@isilon.com>
To:        "FreeBSD Arch" <arch@freebsd.org>
Cc:        Marcel Moolenaar <xcllnt@mac.com>
Subject:   RE: On errno
Message-ID:  <06D5F9F6F655AD4C92E28B662F7F853E02930FBC@seaxch09.desktop.isilon.com>
In-Reply-To: <FE53FDC4-6416-458C-A10C-C2C70A085C83@mac.com>
References:  <8321954E-5CFF-45F9-9F87-BE83659E4C8D@mac.com> <FE53FDC4-6416-458C-A10C-C2C70A085C83@mac.com>

next in thread | previous in thread | raw e-mail | index | archive | help
> Augmentation seems logical. Does anyone know if this has been done
> in some OS already?

AIX version 6.0 has a kerrno_t type which contains the 8-bit standard
error code, as well as basically implementation defined bits that define
where the error came from.  This is for the kernel and kernel
extensions; for binary and source compatibility reasons the existing
interfaces could not be changed, but new interfaces used the new return
type.

I wasn't completely happy with the way it was done, but basically
<sys/kerrno.h> defined a 12-bit block of the kerrno_t that defined which
"namespace" the error came with, and parceled out a bunch for the known
AIX components with a bunch of unused ones too.  So a kerrno_t looked
like:

(32-bit)
1b |
[12 bits identifying a larger namespace like which header] |
[11 bits identifying which specific error return from that header] |
[8 bits for errno]

(64-bit)

0xEEEE |
0x0000 |
[12 bits identifying a larger namespace like which header] |
[12 bits identifying which specific error return from that header] |
[8 bits for errno]

Using 0xEEEE was an eye-catcher, plus the error was negative.  Similarly
the 32-bit errors are negative, which means that functions can continue
to return single positive scalars in success cases that contain
meaningful information, instead of requiring a reference parameter.

So e.g. kerrno.h parceled out the namespace like:

__SYSVMM_BLOCK_00		0x008
__SYSPROC_BLOCK_00	0x010
__DMA_BLOCK_00		0x018
...

If a component wanted to use one "namespace" per header file, there was
generally room for it.

And then in each shipped header file were unique defines for each reason
code, like:

#define EINVAL_XMEMDMA_BADADDRESS	KERROR(EINVAL, __DMA_BLOCK_00,
0x001) #define ENOENT_XMEMDMA_YOUSUCK	KERROR(ENOENT, __DMA_BLOCK_00,
0x002)

(non-shipped headers didn't always need to enumerate the unique error
codes in the header, but instead in the source file, because the callers
weren't expected to look for a specific error)

The code then returned somewhat ugly looking codes like
EINVAL_XMEMDMA_BADADDRESS.  But they could be explicitly compared.  The
kernel also had an awk script that generated a .txt file that listed all
the names and the hex value they were defined as; this was useful for
doing lookups of whatever error codes we were looking at at the time.
Something better could probably be done there.

I don't recall that AIX finished out the story with user-space.  But
these kerrno_t's were extremely useful for debugging any component that
had plumbed itself fully; no more guessing at the 23 reasons it could
return EINVAL; no more wondering in which subroutine the error was
produced.

So yeah, it isn't perfect and there's probably a better way, but it was
definitely better than nothing.

Discuss. :-)

Cheers,
matthew




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?06D5F9F6F655AD4C92E28B662F7F853E02930FBC>