Hi all I am writing a program (API server which implements API and support for LX format executables found in OS/2 operating system). So, it parses an executable, applies fixups and starts it. At the moment it loads a simple executable which calls a single API printing a string on a screen. It generally works, but I got strange IPC problems. There is a function in a server, trampoline() which starts a previously prepared executable in a separate task (it is a kind of wrapper around that executable). After executable termination, trampoline() must synchronize with the server, passing it a message about termination. Then the API server can terminate itself. For synchronization, I tried two ways: 1) sending a message to main server thread through DICE interfaces. As I understand, a problem can be with that client and server stubs are linked to a single program. A code of trampoline() looks like that: static void trampoline(unsigned long esp_data, unsigned long eip_data) { CORBA_Environment env = dice_default_environment; l4_threadid_t dest; l4_msgdope_t result; l4_umword_t w0, w1; int err; asm( "pop %%eax\n" "pop %%eax\n" "movl %[esp_data], %%eax \n" /* Put old esp in eax */ "movl %[eip_data], %%ecx \n" "movl %%ebp, %%edx \n" /* Copy ebp to edx. Base pointer for this functions local variables.*/ "movl %%eax, %%esp \n" /* Copy eax to esp. Stack pointer*/ /* We have changed the stack so it now points to out LX image.*/ "call *%%ecx \n" /* Call our main() */ : :[esp_data] "m" (esp_data), /* esp+ data_mmap+8+*/ [ebp_data] "m" (ebp_data), /* esp+ data_mmap+8+*/ [eip_data] "m" (eip_data)); LOG("task end"); // query OS/2 server task id names_query_name("os2server", &dest) ; LOG("os2server uid=%x.%x", dest.id.task, dest.id.lthread); // send a signal about termination to OS/2 server env.utcb = l4_utcb_get(); os2server_wakeup_call (&dest, &env); if (DICE_HAS_EXCEPTION(&env)) printf("Error: %d.%d", DICE_EXCEPTION_MAJOR(&env), DICE_EXCEPTION_MINOR(&env)); } Without setting env.utcb to UTCB pointer, it traps because of null pointer dereferencing. (In os2server_wakeup_call() function code generated by DICE. This is the disassembly code: _os2server_wakeup_wakeup_wakeup_msg_buffer_t *_dice_msg_buffer = (_os2server_wakeup_wakeup_wakeup_msg_buffer_t*)_dice_corba_env->utcb->values; 1806a19: 8b 45 0c mov 0xc(%ebp),%eax 1806a1c: 8b 40 10 mov 0x10(%eax),%eax 1806a1f: 89 45 dc mov %eax,0xffffffdc(%ebp) l4_umword_t _exception __attribute__ ((unused)); l4_umword_t _dummy __attribute__ ((unused)); l4_msgtag_t tag_dummy __attribute__ ((unused)) = l4_msgtag(0,0,0,0); l4_msgdope_t _dice_result = { raw: 0 }; _dice_msg_buffer->wakeup_wakeup_in._dice_opcode = _OS2SERVER_WAKEUP_WAKEUP_OPCODE; 1806a22: c7 00 01 00 10 00 movl $0x100001,(%eax) -- it traps when assigning an opcode at the last instruction. I thought this is because of UTCB pointer in env points to OS/2 server's main thread UTCB but trampoline() executes in different task, so UTCB is other. When I added UTCB pointer, it stopped trapping but I got DICEexception with MAJOR code 2 and MINOR 2 (IPC error). On server side, a function os2server_wakeup_component() must be called which intended to reset a semaphore, on which a main thread waits for trampoline() termination: void DICE_CV os2server_wakeup_component (CORBA_Object _dice_corba_obj, CORBA_Server_Environment *_dice_corba_env) { LOG("wakeup called"); l4semaphore_up(&sem); } -- It never gets called because of IPC error in os2server_wakeup_call (). 2) Also, I tried another way -- there is a thread on the server side waiting for a message (I decided to create another thread besides the main one to not interfere with DICE): static void os2server_wakeup_thread (void) { l4_msgdope_t result; l4_threadid_t src, id; l4_umword_t w0, w1; /* because of l4thread_create(..., L4THREAD_CREATE_SYNC) */ l4thread_started(0); names_register("os2server.wakeup"); while (1) { LOG("waiting for message"); l4_ipc_wait (&src, L4_IPC_SHORT_MSG, &w0, &w1, L4_IPC_NEVER, &result); LOG("message received"); if (w0 == 0 && w1 == 0) { l4semaphore_up(&sem); LOG("semaphore reset"); } } } trampoline() code is modified this way: static void trampoline(unsigned long esp_data, unsigned long eip_data) { l4_threadid_t dest; l4_msgdope_t result; l4_umword_t w0, w1; int err; asm( "pop %%eax\n" "pop %%eax\n" "movl %[esp_data], %%eax \n" /* Put old esp in eax */ "movl %[eip_data], %%ecx \n" "movl %%ebp, %%edx \n" /* Copy ebp to edx. Base pointer for this functions local variables.*/ "movl %%eax, %%esp \n" /* Copy eax to esp. Stack pointer*/ /* We have changed the stack so it now points to out LX image.*/ "call *%%ecx \n" /* Call our main() */ : :[esp_data] "m" (esp_data), /* esp+ data_mmap+8+*/ [ebp_data] "m" (ebp_data), /* esp+ data_mmap+8+*/ [eip_data] "m" (eip_data)); LOG("task end"); if (!names_waitfor_name("os2server.wakeup", &dest, 10000)) LOG("wakeup thread not found"); else LOG("wakeup thread found, uid=%x.%x", dest.id.task, dest.id.lthread); w0 = 0; w1 = 0; err = l4_ipc_send(dest, L4_IPC_SHORT_MSG, w0, w1, L4_IPC_NEVER, &result); if (err) LOG("error: %ld", err); else LOG("message transmitted"); LOG("msgdope = %lu", result); LOG("mini33 exit"); } This way I get an IPC error too. The return code from l4_ipc_send() is equal to 16 but msgdope is clear (zeroes). I found a description of errors returned in message dopes but what means a return code of 16, I don't know. (For message dope, a error code of 0x10 means that source or destination does not exist, but I am sure it exists) So, l4_ipc_send() exits and l4_ipc_wait() on other side never exits. Maybe, someone can help understanding why it won't work? Thanks in advance.
participants (1)
-
Valery V. Sedletski