Exception propagation in C

J

Jens Gustedt

Am 01/02/2012 08:02 PM, schrieb BGB:
the main issue with directly using braces is that it doesn't give
anywhere to un-register the exception.

The 'TRY' can hide a lot of things. In particular you can do scope
bound resource manangement by using "for" scope variables. See e.g

http://gustedt.wordpress.com/2010/08/14/scope-bound-resource-management-with-for-scopes/

catch with an integer could also use a FOURCC for well-known / named
exceptions.

FOURCC ??
my current exception system uses dynamically-typed references
(generally, type-checking would be done as part of catching an
exception). generally, my type-system identifies types by type-name
strings (additionally, class/instance objects and certain C structs may
also be used, as these are built on top of the dynamic type system).

Throwing void* instead of int would also be an option, indeed. You
then could easily develop a system that uses some sort of struct to
transfer the exception information.

But, I'd prefer the solution I indicated over that. I would be
basically a (hidden) switch statement for the CATCH block, things that
look familiar to C programmers. And when throwing pointers to objects
you'd always have the problem of the responsability for the allocated
space.

Jens
 
R

Rod Pemberton

....
If it were to be set anywhere other than during a function call, how would
you know when to check, even with volatile?

Polling.


Could you be more specific? I have a hard time picturing something that
doesn't involve either a broken C environment or something that I wouldn't
describe as single-threaded.

Parallel.


Rod Pemberton
 
J

James Harris

....
   cmp [thread_excep], 0
....

You'd have to maintain a different set of page tables on each CPU
in order to keep the address constant...

I don't follow. The machine word cannot be shared among processes
executing in parallel. In fact each thread would have to have its own
copy.
If you want exceptions, why not use a language with exceptions?

1. Exceptions are not the only requirement.

2. The scheme proposed will work between languages. I don't intend the
use of many languages but as an example, a Pascal routine could call
an assembly routine which could call a C routine which could call
another assembly routine and all of them could follow the same, very
fast, exception propagation protocol. (More accurately, the point is
that each would very quickly skip non-exceptions while still handling
exceptions.)
If you're OK with explicit error checking, use the return value or a
pointer argument.

This is definitely a possibility. The regularity of calling routines
a() and b() as follows is quite tempting.

if (ex = a()) {if (handler(&ex)) return ex;)
if (ex = b()) {if (handler(&ex)) return ex;}

Naturally, handler() would return non-zero if it did not handle the
exception and the normal returns from a() and b() would be &vars.
Perhaps the main things against it are,

1. It adds a parameter to each call. There is the question of whether
a return be added to routines which cannot generate an exception just
to maintain the regularity. The form is not used in system calls or C
library routines and is unfamiliar to many.

2. It wouldn't look quite so regular when the arguments are included.
Nor would it look so neat when many single-line statements had to be
converted to two lines because of the length of the text.

3. It doesn't allow a sticky exception state such as

a();
b();
if (thread_excep) /* An exception occurred in a() or b() */

If I wanted to add a sticky state I suppose I could write

if (ex |= b()) ...

but that puts the OR instruction (and possibly a memory update) into
the main non-exception processing path so would be slower in the
normal processing case.

I'm not ruling it out completely. It does do away with the goto.

James
 
B

BGB

On Dec 31 2011, 2:24 am, BGB<[email protected]> wrote:
...
Yes. The task switcher would include code along the lines of
push [thread_excep]
for the outgoing task and, for the incoming task,
pop [thread_excep]
Since the word would be checked many times between task switches this
is much faster than following a structure off FS or similar.

possibly, however the issue then partly becomes:
how does the task switcher know where the variable is?...

Isn't this easy if you have a flat address space: just put the
variable at a fixed location?

if the task switcher is part of the OS kernel (it generally is), then it
does not have direct visibility of variables declared in a user-space
binary.

Does this mean that the global, G, in the following would not be
accessed directly?

int G;
void sub() {
while (G> 0) {
G -= 1;
sub();
}
}
int main(int argc, char **argv) {
G = argc;
sub();
return 0;
}

it depends on the target (CPU mode, compilation mode, and object format).

if compiling for PE/COFF (EXE or DLL), it will be accessed directly.


for ELF, in this case it will generally be accessed indirectly via the
GOT (since the compiler will not know at this point where the variable
is declared, a "common" variable could be either within the local ".bss"
segment, or potentially imported from another SO, but this is only known
to the linker).

if it were initialized or static:
static int G;
or:
int G=0;

then the compiler would know that it was defined in the same compilation
unit, in which case:
on 32-bit x86, it will depend on whether or not this is PIC code (which
will generally depend on whether or not this is a Shared-Object).

on x86-64, the CPU has RIP-relative addressing, and so will presumably
use this to access the variable (for both SO's and non-SO binaries).

also, segment overrides are fairly cheap.

True. It obviously depends on the CPU but in my tests, while segment
loading cost a bit, segment overrides were completely free.

yep.

the cheapest option then would probably be to include whatever magic
state directly into the TEB/TIB/whatever, then be like:
mov eax, [fs:address]

in some cases, accessing a variable this way could in-fact be
potentially cheaper than accessing a true global.

As mentioned, I would expect a file-scope global to be accessed
directly - as a machine word at a location that gets filled-in by the
linker. Am I wrong? Are you are thinking of library code?

...

I am thinking for the case where an OS scheduler needs access to a
userspace global variable.

the kernel can't easily know about this case, unless something "special"
is done.

Why is this no good? There can be any number of user exception types
so it's not possible to have one bit for each. The best I could think
of was to have one bit to indicate a user exception and functions to
examine as much other detail as needed.

exceptions don't generally work this way.
yes, "one bit per type for every type" is absurd, but using one bit
per-type for certain exceptions but not others, isn't much better.

If only one exception at a time is needed that makes things
significantly easier. But is only one needed? I was thinking of
exceptions caused in exception handlers. For example, the exception
handler divides by the number it first thought of and triggers an
overflow or it checks an array index and finds it out of bounds. What
does the system do?

It could leave the first exception in place - after all that was the
root cause. Or it could replace the exception information with its own
- after all it has an internal fault. Neither seems obviously best. It
might be best to keep both indications until both have been either
resolved or reported ... but it would be easier to handle if only one
was kept.

most exception handler systems will simply ignore the first and rethrow
the next.

some systems (those with Resumable Exceptions, such as Win32 SEH),
generally nest them sort of like a stack, so (AFAIK) exceptions are
handled in LIFO order provided all are resumable exceptions. if a
non-resumable exception occurs, then it will unwind and presumably there
is no way to handle prior exceptions.

If an exception "can't be thrown"? What would prevent it being thrown?

stack overflow;
crash within dispatcher;
(Win64) if function prologues/epilogues are missing or illegible;
....

Not very good, though, is it! In reality I think that Windows or any
OS will handle almost all exceptions. A BSOD should only occur on a
hardware failure such as a machine-check exception. (It looks like
Windows does run third-party drivers as privileged this increasing its
vulnerability many-fold.)

nope.

apparently the Windows kernel treats pretty much any CPU exception
within the kernel as a BSOD-causing offense.

this leads to more BSODs, potentially, but the argument is that if
something has gone wrong in the kernel, it is better to try to kill the
system "gracefully" than to continue on in a potentially inconsistent state.

AFAIK, Linux tries a little harder, displaying a register dump and
similar and tries to recover, or failing this does a "kernel panic".


user-space exceptions can be handled more gracefully (raising signals or
invoking exception handlers, ...).

interestingly, the "This program has performed an illegal operation and
must be shut down." message is also an exception handler. if one crashes
the application hard enough, one will not see this, and instead the
process simply/silently dies/disappears.

in the past, this could leave dead/phantom windows (don't redraw, can't
be moved or closed, ...) but I suspect newer versions have addressed
this (any windows owned by the process are automatically destroyed even
if the process dies rather non-gracefully...).

I could be wrong on the details here, mostly speaking from old memories.


Following your analogy of a CPU you could perhaps think of each
exception condition as an interrupt line that gets asserted until the
condition causing the interrupt has been resolved. I know, as an
analogy it's not perfect. :-(

flags and similar are used here.

so, normal interrupt occurs:
transfers to handler (and temporarily disables other interrupts);
handler does its thing;
iret (return from interrupt, restores prior CPU state, although GPRs/...
generally need to be manually saved/restored).

if things go bad in the first handler, then a double-fault occurs (a
dedicated special interrupt).

if the DF handler itself fails, the CPU reboots.


AFAIK, older CPUs would essentially just ignore whatever (maskable)
interrupts occurred during the handler, but newer ones will essentially
queue them and handle them in a FIFO order.


my memory gets a bit foggy here, as it has been a long time since I have
messed with this stuff...

I'd like to understand why they would be. I tried compiling the code
above with gcc and it seems to refer to G directly such as in sub()
the compiler generates

mov DWORD PTR G, %eax

but, with which OS and what compiler settings.

if this was Linux-i386 and "-shared" or "-fpic" was given, one would not
likely see a global being loaded this way.

if it was on Win32, then the above is what one would expect to see.

I know. I found that in some systems there is a call which returns the
address of errno. In that case the compiler should (hopefully)
remember that address for each use in a function.

this depends...

in most cases, it probably wont, since the compiler can't be sure that
the function wont return a different address each time (though I wont
rule out the possibility of some sort of a "this function will always
return the same value" modifier/attribute).

Don't forget the original intention was speed. The point of a status
word, as you call it, is to allow exception handling (or, non-
handling) quickly. It is not an end in itself but a means of adding
exceptions to C in a way that recognises exceptions in the right
places while having the lowest possible impact on overall performance.

it is debatable that this is actually faster...

the problem is if the status is checked in each function (possibly
multiple times) then this may infact cost more overall than even
registering/unregistering exception handlers.

handlers capable of reflective unwinding (the GCC/DWARF strategy, Win64
SEH), only have a cost if an exception occurs, and are free otherwise
(apart from debatable "possibly contrivance" in the prologue/epilogue
case WRT Win64 SEH).


in my own (mostly unsused) ABI, I had done something like:
push ebp
mov ebp, esp
push ... ;push-register sequence, like in Win64
sub esp, ... ;space for locals/...
....
lea esp, [ebp-offs]
pop ...
pop ebp
ret
nop [magic_info] ;function metadata (optional)

this preserved a property that is desirable from typical with cdecl, but
is lost with both Win64 and SysV/AMD64: the ability to backtrack simply
using an EBP/RBP chain (with Win64, one has to unwind using awkward
logic, and on SysV/AMD64 one may be SOL apart from using DWARF as the
ABI does not mandate any sort of standardized frame pointer).

in the 32-bit case, my ABI would have been otherwise nearly identical to
cdecl, only differing in the use of special prologues and epilogues.


the 64-case was mostly similar to the 32-bit case and Win64, differing
from Win64 mostly in that the first 4 arguments are always passed on the
stack (and RBP being reserved as the frame pointer).

(gluing between them would generally be little more than a few 'mov'
instructions or similar).


in practice, I had mostly just used the Win64 and SysV/AMD64 ABIs (and a
custom name-mangling scheme). my implementation of the SysV/AMD64 ABI
was technically kind of crappy though, as I didn't bother much with
complex edge cases (passing/returning structs in registers, ...), and
due to technical reasons, arguments were stored to the stack and loaded
into registers just before the call operation.

otherwise, cross-ABI calls would require the use of costly
transfer-thunks (which basically save/restore registers and re-pack
argument lists, so a poorly-implemented SysV/AMD64 was at least a little
faster).

or such...
 
B

BGB

Am 01/02/2012 08:02 PM, schrieb BGB:

The 'TRY' can hide a lot of things. In particular you can do scope
bound resource manangement by using "for" scope variables. See e.g

http://gustedt.wordpress.com/2010/08/14/scope-bound-resource-management-with-for-scopes/

didn't think of this...

FOURCC ??

http://en.wikipedia.org/wiki/FOURCC

basically, 4 ASCII characters are encoded into a 32-bit integer, and
used as a magic number.

if one only allows printable ASCII characters, then one has all numbers
less than 0x20202020, or 538976288, which may be used as raw integer
values. similarly, all numbers >= 0x7F000000 are also outside the valid
printable ASCII range (this includes the entire set of negative integers
as well).

Throwing void* instead of int would also be an option, indeed. You
then could easily develop a system that uses some sort of struct to
transfer the exception information.

what I am doing is a bit more involved than this.
note "dynamically typed": this isn't something nearly so simple as a raw
void pointer to a struct.


in my case though, it "may" be a pointer, but the type on the other end
depends on what is pointed-to.

one could potentially just pass the FOURCC as a fixnum, although a TWOCC
or THREECC would be better (since a fixnum doesn't have the full 32-bit
range on a 32-bit system, and any value outside of a 28-bit range in my
system would require using a boxed value, which is more expensive).

so, a THREECC would pass an exception name like 'GPF', 'IOX', 'BND', ...

But, I'd prefer the solution I indicated over that. I would be
basically a (hidden) switch statement for the CATCH block, things that
look familiar to C programmers. And when throwing pointers to objects
you'd always have the problem of the responsability for the allocated
space.

only if it is a pointer to some sort of malloc()'ed memory or similar.

other options:
using a garbage collector (allocate and forget, the GC may reclaim it
later);
the reference doesn't actually point to any existent memory (it is an
abstract value, such as a handle or fixnum);
ownership doesn't transfer: some other 3rd party maintains
responsibility (such as the exception-dispatch subsystem);
....
 
J

jacob navia

Le 06/01/12 21:05, BGB a écrit :
it is debatable that this is actually faster...

the problem is if the status is checked in each function (possibly
multiple times) then this may infact cost more overall than even
registering/unregistering exception handlers.

handlers capable of reflective unwinding (the GCC/DWARF strategy, Win64
SEH), only have a cost if an exception occurs, and are free otherwise
(apart from debatable "possibly contrivance" in the prologue/epilogue
case WRT Win64 SEH).

I was the first to answer Mr Harris post (Dec 29th)

He never answered or acknowldged my post even if I pointed him to:

<quote from my message from Dec 29th>
Look at the exception handling code in
gcc. It implements an abstract machine that gets opcodes from a series
of tables generated by the compiler.

.... snip ...

You should also look at the code of gcc. Specifically look in the
"except.c" file and in the unwind-xx-fde files. There you will
find the implementation
<end quote>

He ignored my advice and tried to defend his completely crazy schema
with some "machine word" global variable.

This is surprising since he declared (in another thread) that "gcc" was
his "leight weight" compiler that he would use.

Either:

1 Mr Harris doesn't *really* know what he is talking about

2 He wants to eliminate the exception handling mechanism of his
preferred compiler and figure out a new one AND hack gcc to
implement that...

Since the second looks like a LOT of development time (I would guess at
least 6 months full time) I would rather say that option (1) is more
likely, unless of curse, he doesn't KNOW about DWARF/gcc/exception
handling what would confirm (1) but make comprehensible why he is
proposing (2).
 
R

Rod Pemberton

....

Even if one is unfamiliar with FOURCC, we are familiar with four character
ID3 Tags:
http://en.wikipedia.org/wiki/Id3
basically, 4 ASCII characters are encoded into a 32-bit integer, and
used as a magic number.

Interesting idea ... at least for a.o.d. ... When I first read that, I had
no idea what you were rambling about. The 32-bit integer could function as
both a unique identifier, or hash-like value, and provide information since
it'd be readable as ASCII too. I like it. 0xDEADBEEF on "steroids" ...


Rod Pemberton
(FYI, follow-ups set to a.o.d.)
 
E

Ed Coran

jacob said:
Le 06/01/12 21:05, BGB a écrit :

I was the first to answer Mr Harris post (Dec 29th)

And that is significant why?
He never answered or acknowldged my post even if I pointed him to:

Uh oh, you think newsgroup posts are akin to talking to people for real?
He ignored my advice

You are his advisor? I have done a little bit of consulting and know that
all that matters in the legal substrate is the contract. So, what are you
all up about, Jack? Are you in love with him? Is this beyond "the law"?
Either:

1 Mr Harris doesn't *really* know what he is talking about

Or he does not accept you as "his master"? Have you considered that you
are unimportant to him?
2 He wants to eliminate the exception handling mechanism of his
preferred compiler and figure out a new one AND hack gcc to
implement that...

And if he solved that problem, your toil and labor would be all for
naught? Really now. His disregard for emperialism is, surely, at the
highest disregard, I mean we are all the same huh, but he breached that?

You seek a "kindred spirit", surely. Surely I'm just here to **** you up.
Ya think?
 
J

jacob navia

Le 07/01/12 05:24, Ed Coran a écrit :

Mr Coran:

[snip personal attacks]

Nothing in your message goes to the problem I have been repeating for a
while here:

Exception handling is a wide field of research that has been studied
for years by many bright people with some implementations like gcc's
open for study with their source code.

The idea of replacing the fruit of all those efforts with something
like a global variable that must be constantly POLLED by user code
is such a completely NUTS idea that I recommended mr Harris to READ THE
LITERATURE about the subject before proposing such a ridiciulous
"solution".

Your personal attacks do not change anything about this state of affairs
and really only display your total lack of arguments.

Yes, what else can you say than:

<quote>
Surely I'm just here to **** you up
<end quote>

THAT is the level of your arguemnts.

Well, to be able to insult me, Sir, it is first necessary that I give
some importantce to what you say.

Yours sincerely

Jacob Navia
 
J

James Harris

Le 06/01/12 21:05, BGB a écrit :




I was the first to answer Mr Harris post (Dec 29th)

He never answered or acknowldged my post even if I pointed him to:

Just because I didn't reply to you directly don't think I didn't read
your post. I did, more than once, so don't be offended. It is not
feasible to reply to everyone!

James
 
J

James Harris

....
if the task switcher is part of the OS kernel (it generally is), then it
does not have direct visibility of variables declared in a user-space
binary.

The intention is the other way round. Rather than the OS accessing
task space the tasks can access a fixed location in the kernel space.
For example, say the indicator variable is called task_excep and is
actually at location 4100. With a flat address space the linker should
be able to resolve the label to that address shouldn't it? (Though see
my response below to your point about PIC.)

....
it depends on the target (CPU mode, compilation mode, and object format).

if compiling for PE/COFF (EXE or DLL), it will be accessed directly.

for ELF, in this case it will generally be accessed indirectly via the
GOT (since the compiler will not know at this point where the variable
is declared, a "common" variable could be either within the local ".bss"
segment, or potentially imported from another SO, but this is only known
to the linker).

if it were initialized or static:
static int G;
or:
int G=0;

then the compiler would know that it was defined in the same compilation
unit, in which case:
on 32-bit x86, it will depend on whether or not this is PIC code (which
will generally depend on whether or not this is a Shared-Object).

Thanks for pointing this out. Normal elf32 from GCC and was fine. It
just issued a simple access. When I added the -fpic option you
mentioned below it tried to access it via the GOT. That would be a bit
of a pain, given my desire for speed. That's a pretty cumbersome
mechanism for a variable at a fixed location in the address space but
there's maybe no way to tell the compiler enough that it understands.
For the code, I'm not sure that PIC would be necessary. Do you know
what else it does on GCC, especially as x86 code is generally position-
independent anyway? Branches and jumps are usually relative without
specifying PIC. Is it just for data accesses, for example?
on x86-64, the CPU has RIP-relative addressing, and so will presumably
use this to access the variable (for both SO's and non-SO binaries).

The thing is, the program would not necessarily be loaded at the same
address in each address space so the RIP-relative offset to a fixed
location doesn't work. OT but RIP-relative data addressing is bearable
for reading constants but otherwise is a pretty awful addition, IMHO.

None of these things should be a problem, though. The default settings
in C seemed fine.

....
I am thinking for the case where an OS scheduler needs access to a
userspace global variable.

the kernel can't easily know about this case, unless something "special"
is done.

As mentioned, it's the other way round. Each task needs access to a
machine word that belongs to the kernel. I can't see anything special
being needed. Am I missing something? The idea of a symbolic name
rather than an address is that it can be resolved by the link step.

....
exceptions don't generally work this way.
yes, "one bit per type for every type" is absurd, but using one bit
per-type for certain exceptions but not others, isn't much better.
OK

....



flags and similar are used here.

so, normal interrupt occurs:
transfers to handler (and temporarily disables other interrupts);
handler does its thing;
iret (return from interrupt, restores prior CPU state, although GPRs/...
generally need to be manually saved/restored).

if things go bad in the first handler, then a double-fault occurs (a
dedicated special interrupt).

if the DF handler itself fails, the CPU reboots.

It seems you are thinking principally of the CPU exception interrupts.
I was thinking more of the hardware interrupt lines but it's not too
important. It wasn't a very good analogy anyway.

....
but, with which OS and what compiler settings.

if this was Linux-i386 and "-shared" or "-fpic" was given, one would not
likely see a global being loaded this way.

As above, you are right about -fpic. -shared seemed to make no
difference.
if it was on Win32, then the above is what one would expect to see.

Do you mean that a compiler using Win32's version of position
independent code would access G directly?

....
this depends...

in most cases, it probably wont, since the compiler can't be sure that
the function wont return a different address each time (though I wont
rule out the possibility of some sort of a "this function will always
return the same value" modifier/attribute).

OK. How about at the top of a function,

int *erloc = &errno;

Then after each call,

if (*erloc)

I've not worked this through. Just a thought. As Kirk says, I like to
think there are always options. :)

....
it is debatable that this is actually faster...

the problem is if the status is checked in each function (possibly
multiple times) then this may infact cost more overall than even
registering/unregistering exception handlers.

I don't see your mathematics on this. I can't think of a perfect
analogy but it is similar to taking a C program ending with

return;

and changing it to

return 1;

How many people would complain that that slowed down their code?

Your PIC example would not be so fast, if written in C, where it goes
via the GOT. Position-independent assembly language would not be a
problem. Non-PIC code in either language doesn't see to be a problem
either.

The only thing I could think of which would be ostensibly faster is
just to test the carry flag on return

call subroutine
jc exception

However, that is no good for these reasons

1. Time would still be required to set or clear carry in the
subroutine.
2. C does not support access to the carry flag.

So, overall, it would not be faster and may be slower in some cases,
and could not be written in C.
handlers capable of reflective unwinding (the GCC/DWARF strategy, Win64
SEH), only have a cost if an exception occurs, and are free otherwise
(apart from debatable "possibly contrivance" in the prologue/epilogue
case WRT Win64 SEH).

in my own (mostly unsused) ABI, I had done something like:
push ebp
mov ebp, esp
push ... ;push-register sequence, like in Win64
sub esp, ... ;space for locals/...
...
lea esp, [ebp-offs]
pop ...
pop ebp
ret
nop [magic_info] ;function metadata (optional)

OK. This seems similar to a standard prologue and epilogue.
this preserved a property that is desirable from typical with cdecl, but
is lost with both Win64 and SysV/AMD64: the ability to backtrack simply
using an EBP/RBP chain (with Win64, one has to unwind using awkward
logic, and on SysV/AMD64 one may be SOL apart from using DWARF as the
ABI does not mandate any sort of standardized frame pointer).

OK. FWIW if you used a test-on-return as per my proposal you could
build the stack trace on return, even without use of ebp-style stack
frames. That's what I plan to do. Of course, it will only build a
stack trace report between where the exception occurs and where it is
handled.

James
 
J

jacob navia

Le 08/01/12 23:20, James Harris a écrit :
As mentioned, it's the other way round. Each task needs access to a
machine word that belongs to the kernel. I can't see anything special
being needed. Am I missing something?

Yes, you are missing everything:

1) Many people including me have told you that each thread needs an
exception handler, in a multi-threaded environment. It can't be
just a machine word somewhere. It must be thread local storage

2) Accessing that machine word by polling, as you propose can't be done
in one instruction since you need the thread ID to be able to access
the thread local storage.

3) You need exclusive access to that machine word. You do not want other
process to write to it when you are reading. Remember that today's
CPUs have several cores. Having a thread gain exclusive access would
BLOCK all other threads since they are constantly polling that
famous machine word... If a thread gains exclusive access to that
address and then dies without releasing the lock the PROCESS STOPS.
All threads are blocked.

I could go on but what would be the point?

Can you explain why the existing schemas that have been developed
through many years of usage and debugging do not please you?

Why do you feel compelled to reinvent the wheel by proposing a
square wheel?

HINT: Wheels should be round :)

HINT: Exception handlers are invoked by the OS or a throw in a given
thread and walk the stack seeking a handler using the tables
generated by the compiler
 
J

jacob navia

Le 09/01/12 00:29, Scott Wood a écrit :
From glancing at its output, it seems GCC is able to make pretty extensive
use of RIP-relative addressing, and not just for constants.

-Scott

Using Macintosh OS X you have ONLY RIP addressing! I had to rewrite
most of lcc's backend to make it run there.

Apple has always been fan of relative addressing.
 
J

James Harris

Le 08/01/12 23:20, James Harris a écrit :

The above relates to the initial option 3 so, sticking to that....
Yes, you are missing everything:

Are you sure it's not that you totally misunderstand the idea?
1) Many people including me have told you that each thread needs an
    exception handler, in a multi-threaded environment. It can't be
    just a machine word somewhere. It must be thread local storage

This is TLS. I stated that in the initial post.
2) Accessing that machine word by polling, as you propose can't be done
    in one instruction since you need the thread ID to be able to access
    the thread local storage.

No, for option 3 the word is changed on a thread switch. I have
explained this too.

Checking back, if you view this discussion as a hierarchy see what is
currently the seventh message, a reply I made to BGB.
3) You need exclusive access to that machine word. You do not want other
    process to write to it when you are reading. Remember that today's
    CPUs have several cores. Having a thread gain exclusive access would
    BLOCK all other threads since they are constantly polling that
    famous machine word... If a thread gains exclusive access to that
    address and then dies without releasing the lock the PROCESS STOPS.
    All threads are blocked.

The word is specific to a thread, not to a process, not to a CPU, not
to a machine.
I could go on but what would be the point?

Agreed. Please don't. :)

James
 
E

Ed Coran

jacob navia said:
Le 07/01/12 05:24, Ed Coran a écrit :

Mr Coran:

[snip personal attacks]

Nothing in your message goes to the problem I have been repeating for a
while here:

Exception handling is a wide field of research that has been studied
for years by many bright people with some implementations like gcc's
open for study with their source code.

Surely by some of those lovely people that gave us C and C++! (See what's
wrong with your stance in the above statement now?)
The idea of replacing the fruit of all those efforts with something
like a global variable that must be constantly POLLED by user code
is such a completely NUTS idea that I recommended mr Harris to READ THE
LITERATURE about the subject before proposing such a ridiciulous
"solution".

I must have missed the part where he suggested polling as some kind of
ultimate general solution. Indeed, wasn't his OP surveying the landscape
of ideas on the subject, and in particular, as a retrofit for C while
still being 100% legal C? You wouldn't be contriving something in attempt
to seem somehow superior to him, now would you?

(OK, noted: no more remote humour when replying to your thread. It's hard
to assess whether posters just know literal English or the "richer"
language that it can be).
 
E

Ed Coran

James said:
This is TLS. I stated that in the initial post.

He seems to be limited in his thinking to the existing implementations he
has seen or read about. I.e., there is no indication of out-of-the-box
thinking. His dialog seems to hint toward a C++-like implementation of
exceptions as the be-all and end-all, bottom line, last answer on the
topic of exception handling, which is like much of the rationale often
spewed for C++ features: absurd. His last sentence above is obviously
wrong also.
 
I

Ian Collins

He seems to be limited in his thinking to the existing implementations he
has seen or read about. I.e., there is no indication of out-of-the-box
thinking. His dialog seems to hint toward a C++-like implementation of
exceptions as the be-all and end-all, bottom line, last answer on the
topic of exception handling, which is like much of the rationale often
spewed for C++ features: absurd.

What is the "C++-like implementation of exceptions"? There are many.
 
E

Ed Coran

Ian said:
What is the "C++-like implementation of exceptions"? There are many.

That which behaves, from the language user perspective, not the language
implementor perspective, like C++ exceptions do. Close enough. It would
be incorrect (for lack of a better term which escapes me right now) to
scrutinize what I wrote from a mostly or only detailed implementation
level instead of some higher level perspective of the behavioral
characteristics.
 
8

88888 Dihedral

Ed Coranæ–¼ 2012å¹´1月9日星期一UTC+8下åˆ6時53分32秒寫é“:
That which behaves, from the language user perspective, not the language
implementor perspective, like C++ exceptions do. Close enough. It would
be incorrect (for lack of a better term which escapes me right now) to
scrutinize what I wrote from a mostly or only detailed implementation
level instead of some higher level perspective of the behavioral
characteristics.

For the error handling in C, one has to think what part can fail fist.

The I/O file related part or the heap allocation part should be
classified as checked before used.

Please list all those actions that can be classified as those to be checked before used first in all programming languages.

Of course the choking quick sort in the C standard lib
is another one to be checked.

Now the questions are:
1. how to avoid redundant checks in various functions,
2. if something checked to be ill how to handle these in the run time
efficiently
3. if there are many functions could fail in the run time then
how to control these possible failures in one's programs efficiently
and completely to build a robust system
 
J

James Harris

....
And it's been explained to you that "changed on a thread switch" doesn't
work unless this is CPU-local storage by some other mechanism.

If you mean your comment four days ago, I did reply. I said that I
didn't understand what you meant but you said no more. Not what I
would call 'explained' to me! :-(
 More than
one thread can be running at the same time -- no switching, no opportunity
to swap the magic variable.

I've been puzzling over this. The only thing I can think that might
cause a problem is multiple threads running in the same address space
on different CPUs. Is that what you mean?

James
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,744
Messages
2,569,483
Members
44,903
Latest member
orderPeak8CBDGummies

Latest Threads

Top