gnu-arch-users
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Gnu-arch-users] Nit


From: Tom Lord
Subject: Re: [Gnu-arch-users] Nit
Date: Thu, 23 Oct 2003 09:37:47 -0700 (PDT)



    > From: Andrew Suffield <address@hidden>

    > On Wed, Oct 22, 2003 at 11:58:08AM -0700, Tom Lord wrote:
    >> That's why I think that the address of a string constant works out
    >> better than densely-packed integers:  the linker will give each error
    >> (represented as a string constant) it's own address (in each
    >> executable or process).

    > But you sacrifice the possibility of passing errors between
    > processes, and I can't see any reason why you do that - nothing in
    > your scheme depends on the error values being randomly assigned in
    > every process.

Ok, we can fix that now (and, strangely enough, I have a use for it).
Shades of GError follow.   The general trick is not to require a
global namespace of integer error codes but to permit a global
namespace of pairs:

        (domain, code)

where `domain' is a string that should be stable and have a unique md5
hash, code an integer allocated by the authority that stakes out that
domain name.

The portable number defining an error is 160 bits:

  : md5 sum of domain (128 bits) : code (32 bits) :

If an error type has a NULL domain, a code can be assigned to it
on-demand but, in general the error type is not portable between
processes.  (Or, rather, the process can make up a temporary domain
for itself and send and receive back these errors -- but other
processes won't automatically identify them with their own local error
types.)

Error parameters can be handled somewhat but not in the general case.

Something like this:


struct error_params_vtable;
typedef struct error_params_vtable;

struct error_type
{
  /* short graphical-chars name for the error:
   */
  char * name;

  /* sentence fragment msg for error
   */
  char * msg;

  /* type description of parameters to this kind
   * error.
   */
  struct error_params_vtable * vtable;

  /* optional name of the authority that allocated an error
   * code for this error type.
   */
  char * domain;

  /* error code (within the domain) for this error
   */
  t_uint32 code;


  /* if is_proxy is not 0, then this is not the 
   * definitive struct error_type for this error_type.
   * 
   * The fields name, msg, and domain are not authoritative
   * for this error type.   vtable is authoritative if not 0.
   */
  int is_proxy;

  /* if is_proxy, then proxy_for is either 0 or a pointer
   * to the authoritative struct error_type for this error type.
   */
  struct error_type * proxy_for;

  /* if dom_cached, then domhash_hi and domhash_lo are 
   * an md5sum for the authoritative domain name.
   */
  t_uint64 domhash_hi;
  t_uint64 domhash_lo;

  /* if not 0, a (non-portable) densely packed natural number
   * unique to this error type (not the struct -- the actual 
   * error).
   */
  t_uint domseq;
};

typedef struct error_type * error_type_t;

struct error
{
  struct error_type * type;
  void * params;
};

#define ERROR_TYPE_DECL(NAME, MSG, VT) \
  error_type_t NAME { #NAME, #MSG, VT, 0, };

#define PORTABLE_ERROR_TYPE_DECL(NAME, MSG, DOM, COD) \
  error_type_t NAME { #NAME, MSG, VT, DOM, COD, , 0 };


Ok, so, if you need an error code but don't have an integer allocated
from a central authority, you can declare it with:

  ERROR_TYPE_DECL (err_rmn_crack, "socket to me?", rmn_vtable);

and if you _do_ have an authoritative protable error code
you can use:

  #include "hackerlab/bugs/portable-errors.h"


  PORTABLE_ERROR_TYPE_DECL (err_rmn_crack,
                            "socket to me?",
                            rmn_vtable,
                            HACKERLAB_ERROR,
                            HLERR_RMN_CRACK);

If an error has a domain of NULL, then it is _not_ a portable error
zcode.  (It can be assigned a per-process error code on demand,
though.)

Checking the type of an error becomes more complicated:

  error_is_type (type, err)
  {
    if (type->proxy_for)
       type = type->proxy_for;

    if (error->type->proxy_for)
      error->type = error->type->proxy_for;

    if (type->is_proxy
        && !error->type->is_proxy
        same_dom_and_code (type, error->type))
      {
        type->proxy_for = error->type;
        type = type->proxy_for;
      }

    if (error->type->is_proxy
        && !type->is_proxy
        same_dom_and_code (type, error->type))
      {
        error->type->proxy_for = type;
        error->type = type;
      }

    if (err->type == type)
      return 1;
    else
      return same_dom_and_code (type, error->type);
  }


error_t should really be opaque.   I think the client view of its
internal structure is mostly just:

        char * error_name (err);
        char * error_msg (err);
        int error_code (&domhi, &domlo, &code, err);
        error_type_t error_type (err);

(but people need to use error_is_type or error_types_equal
rather than == to compare error types).

For convenience, we can add:

  t_uint error_type_seq (error_type)
        Return a (non-portable) densely packed
        integer that is unique to this error type.
        

As for error parameters: I don't see any good _generic_ way to make
them RPC friendly, however, the error_t modules itself should come
with some common vtables:

  extern struct error_params_vtable errror_int32_vtable;
  extern struct error_params_vtable errror_uint32_vtable;
  extern struct error_params_vtable errror_int64_vtable;
  extern struct error_params_vtable errror_uint64_vtable;
  extern struct error_params_vtable errror_float_vtable;
  extern struct error_params_vtable errror_float_vtable;
  extern struct error_params_vtable errror_double_vtable;
  extern struct error_params_vtable errror_double_vtable;
  extern struct error_params_vtable errror_string_vtable;
  extern struct error_params_vtable errror_string_array_vtable;

With predictable convenience functions like:

        int error_type_is_string_type (err);
        void error_set_string (err, "foo");
        char * error_get_string (err);

and so forth.

Prbly also worth making a hackerlab authority domain for errno errors
that are (symbolically) reasonably portable.

-t





reply via email to

[Prev in Thread] Current Thread [Next in Thread]