This week I have read the <Mach 3 Kernel Principles> and some relate materials. And I have rewritten the MIG use example in <A programmer's guide to the mach user environment>. I put the code in github. Most of the code is stolen from Anand Babu's example.
Now I have known something about the mig basically. I can answer the question of "What is the S_exception_raise_request()?" .
Firstly, I will describe without debugger stuff. When a task was created, the glibc will created one more thread(so called message thread or signal thread) in the task. The function _hurdsig_init() [glibc/hurd/hurdsig.c] will initialize the exception port of the other thread in the task, and start the signal thread to listen on all the ports. The signal thread will run the _hurd_msgport_recieve() [glibc/hurd/msgportdemux.c] which invoke the mach_msg_server() [glibc/mach/msgserver.c] with the first parameter of msgport_server() as its demux pointer.
After the initialization, the signal thread is blocked until a exception occur. Whenever an exception occurs(for instance, thread A cause an divide zero exception), the mach kernel will suspend the thread A right now, and the kernel will send a exception message to the thread A's exception port on behalf of A. Meanwhile, our signal thread is already listening on the thread A's exception port. So the mach_msg() will return, and invoke the (*demux)() which is pointer to msgport_server() as described above.
Ok, now we will see the magic of mig. In the last line of msgport_server(), it will return _S_exc_server(). The _S_exc_server() is just an demux who generated by mig from the mach/include/mach/exc.defs and will call the S_catch_exception_raise() to handle the exception. S_catch_exception_raise() [glibc/hurd/catch-exc.c] deliver the signal by _hurd_internal_post_signal() [glibc/hurd/hurdsig.c]. Honestly to say, the _hurd_internal_post_signal() function is too complex to understand for me now. I think I will make it clear in the later work. By default, the _hurd_internal_post_signal will invoke the default handler to handle the divide zero exception which just simply terminal the thread A. After this, the whole exception things without debugger is done.
If a task is under the control of gdb, thing will be a little different. Instead of the glibc's _hurd_msgport_recieve(), the gdb will use the the gnu_wait() to listen on the exception port. And then pass the message by (!notify_server() && !exc_server() && !process_reply_server() && !msg_reply_server()). We only care about exc_server() here, it was generated by the mid from gdb/exc_request.defs like above, and will invoke the S_exception_raise_request() who will handle this exception like the situation in S_catch_exception_raise() above.
This is my understand of how exception is thrown and be handled.
Again, the next week goal is to finish the debugger demo.