grub-devel
[Top][All Lists]
Advanced

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

Re: problem in usage of grub_errno...


From: Yoshinori K. Okuji
Subject: Re: problem in usage of grub_errno...
Date: Sat, 10 Dec 2005 14:11:11 +0100
User-agent: KMail/1.7.2

On Saturday 10 December 2005 11:05 am, Vesa Jääskeläinen wrote:
> Changing coding guide of using grub_errno we could probably get this
> issue "working". But then there is still problem with lost error
> messages if subsequent code fails with real error.
>
> If we just zero out grub_errno in code before printing out error(s).
> Then the actual error message will get lost. So it is important not to
> zero out spuriously grub_errno.
>
> Good way of checking for errors could be like:
> --
> grub_errno_t rc;
>
> rc = function_that_could_fail ();
> /* do some stuff here.  */
> if (rc)
>   return rc;

Please do not change it in this way. The error subsystem of GRUB is based on 
the idea of exceptions, that is to say, passing an error to higher levels 
until it is caught explicitly. This is similar to C++, Java, Python or Ruby. 
Unfortunately, C does not support exceptions directly, so we must emulate it. 
So, what we must do is not to ignore an error where it happens.

I use Python as an example. Suppose this code:

def foo():
  bar()

def bar()
  baz()
  print 'bar'

def baz()
  raise RuntimeError, 'baz'

foo()

When executing this, Python does not print 'bar', because the exception raised 
by baz is not caught by bar, and the control is immediately transferred to 
foo.

In C, to emulate this behavior, we must do like this:

void
foo (void)
{
  bar ();
}

void
bar (void)
{
  baz ();
  if (grub_errno != GRUB_ERR_NONE)
    return;
  grub_printf ("bar\n");
}

void
baz (void)
{
  grub_error (GRUB_ERR_SOMETHING, "baz");
}

In other words, if you ignore an error set by calling a function and pass the 
control to another, it violates the semantics. So, strictly speaking, you 
must choose either of these when an error is set:

- deciding to ignore the error explicitly by setting GRUB_ERRNO to 
GRUB_ERR_NONE

- handling the error by returning to the higher level or dealing with the 
error  locally (e.g. printing the error)

We (at least I) sometimes violate this rule by intention when knowing that it 
is safe to ignore an error, simply because it is too heavy to deal with 
errors all the time.

In your situation, things are a bit complicated. In my opinion, all you should 
do is to save error information in a temporary place and reset it afterwards. 
For example, you can define a function like this:

void
grub_error_push (void)
{
  /* Push the current error in a stack and clear GRUB_ERRNO.  */
  ...
}

void
grub_error_pop (void)
{
  /* Pop the previous error and set GRUB_ERRNO.  */
  ...
}

I don't know if this should be stack-based or flat. For example, you can 
allocate space in a function and pass the pointer to a function which saves 
current error information. In this case, functions should be named 
grub_error_save and grub_error_restore.

The difficulty is that it is not very safe to use a heap to allocate space to 
store error information, because such a memory allocation can generate 
another error (due to memory shortage). The possibility is low, but we must 
still consider it.

One way is to allocate such space in advance. For example, if we use the 
stack-based approach (personally I prefer this for consistency), instead of 
allocating space dynamically, we can allocate it statically. That is, at 
linking time or at initialization time. This way limits the maximum number of 
slots arbitrarily, but it should be enough for the reality (e.g. 10).

What do you think?

Okuji





reply via email to

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