From: "Salvador Eduardo Tropea (SET)" To: snarfy AT goodnet DOT com, djgpp AT delorie DOT com Subject: Multithread question Date: Tue, 23 Jul 1996 13:43:31 +0300 (GMT) Message-ID: <9607231343.aa19011@ailin.inti.edu.ar> Hello everybody, specially Josh Turpen, here SET: Topic: Multithreads, specially the LWP package: First the package is good, but like all the new things (fruits ;) is green. I found 2 mayor problems in the package: 1) The Test program asumes 2 things: a) printf is reentrant. b) DOS is reentrant. 2) The kill doesn't kill anybody, or worst kills the program. 1) Please somebody correct me if I'm wrong but: If the 1KHz interrupt (used for task switching) arrives when DOS is printing (or writing to disk or wherever) the DPMI server reflects the IRQ to the protected mode, then the program makes a task switch and if the new task calls to DOS again the result is unpredictable. There are a way to know if DOS is busy: Testing the InDOS flag, so I added the code to avoid a task switch when DOS is busy. This seems to be NOT enough, I don't see the code of printf but seems that printf isn't reentrant. When I run the test some times work and some times doesn't work. There are 2 posibilies: a) I'm making a wrong test of the InDOS flag. b) printf is less reentrant than DOS. So, please, Charles, DJ, Eli or somebody tell me what's going on. (Look the patch for LWP.C to see how I'm testing the InDOS flag). I think that a better test for the routines is a program that only increments a counters in each task, and the printf is only made by the main task. 2) That's a conjuntion of bugs, to test it simply force that one the tasks call to kill before the end of the program and let the others running >kbum<. Patch for LWP.C: --- ..\pp\lwp.c Tue Jul 23 11:24:00 1996 +++ lwp.c Tue Jul 23 11:08:54 1996 @@ -20,8 +20,12 @@ void _lwp_handler(int signum); lwp *_lwp_cur; int _lwp_count; +int _lwp_pid_count; int _crt0_startup_flags = _CRT0_FLAG_LOCK_MEMORY; +// This flag inhibits the task switch when is !=0 +int lwp_critical_semaphore; + /* note this code is different than irq0. It uses _lwp_flag. A last minute desparation move on my part ;P. All of the int(0x15) stuff is used to start the 1024Hz clock moving. I can NOT get IRQ8 to @@ -54,6 +58,30 @@ popl %eax"); } } + +int SelInDOS; +int OffInDOS; + +static int GetInDOSFlag(void) +{ + __dpmi_regs r; + + r.h.ah=0x34; + __dpmi_int(0x21, &r); + if ((SelInDOS=__dpmi_segment_to_descriptor(r.x.es))==-1) + { + printf("Can't allocate a selector\n"); + return 1; + } + OffInDOS=r.x.bx; + + #ifdef DEBUGINFO + printf("InDos: %X:%X\n",r.x.es,r.x.bx); + printf("State: %d\n",_farpeekb(SelInDOS,OffInDOS)); + #endif + return 0; +} + /* Installs the timer interrupt, and installs the exception handler, returns 0 on fail, true when it works */ @@ -66,6 +94,10 @@ printf("Cannot malloc first lwp\n"); exit(1); } + + if (GetInDOSFlag()) + exit(1); + /* circular list */ _lwp_cur->proc = NULL; /* signify this is main()'s process */ @@ -78,18 +110,20 @@ _lwp_event_handler.pm_selector = _go32_my_cs(); _lwp_event_seg = _lwp_event_handler.rm_segment; _lwp_event_off = _lwp_event_handler.rm_offset; - _lwp_regs.x.ax = SET_EVENT; + _lwp_regs.x.ax = SET_EVENT; _lwp_regs.x.es = _lwp_event_seg; _lwp_regs.x.bx = _lwp_event_off; _lwp_regs.x.cx = LARGEST; _lwp_regs.x.dx = LARGEST; _lwp_regs.x.ss = _lwp_regs.x.sp = 0; + /* This hooks the exception handler */ - __lwp_old_handler = signal(SIGILL,_lwp_handler); - + __lwp_old_handler = signal(SIGILL,_lwp_handler); + _lwp_count = 0; + _lwp_pid_count = 0; /* This hooks the interrupt */ _lwp_pm_new_handler.pm_offset =(int) __lwp_pm_timer_hook; @@ -97,13 +131,13 @@ _lwp_flag = 0; _go32_dpmi_get_protected_mode_interrupt_vector(IRQ8, &_lwp_pm_old_handler); _go32_dpmi_chain_protected_mode_interrupt_vector(IRQ8, &_lwp_pm_new_handler); - __dpmi_int(0x15, &_lwp_regs); + __dpmi_int(0x15, &_lwp_regs); _lwp_flag = 1; } int lwp_getpid(void) -{ +{ return(_lwp_cur->lwpid); } @@ -123,7 +157,8 @@ tmp->next = _lwp_cur->next; tmp->next->prev = tmp; _lwp_cur->next = tmp; - tmp->lwpid = ++_lwp_count; + tmp->lwpid = ++_lwp_pid_count; + _lwp_count++; _lwp_cur->proc = proc; if(setjmp(tmp->state)) @@ -143,26 +178,41 @@ int lwp_kill(int lwpid) { int i = 0; - lwp *tmp = (lwp *) malloc(sizeof(lwp)); - memcpy(tmp, _lwp_cur, sizeof(lwp)); + lwp *tmp; + + if (!_lwp_flag || lwp_critical_semaphore!=0 || _farpeekb(SelInDOS,OffInDOS)!=0) + // Hey!! what's going on + return 0; + + _lwp_flag = 0; + tmp=_lwp_cur; while((i<= _lwp_count+1) && (tmp->lwpid != lwpid)) { i++; tmp = tmp->next; } /* went through all of them and wasn't found */ - if(tmp->lwpid != lwpid) + if (tmp->lwpid != lwpid) + { + _lwp_flag = 1; return(0); + } /* now tmp IS the right one to kill */ - _lwp_flag = 0; + #ifdef DEBUGINFO + printf("Hooking: %d with %d and jumping %d\n",tmp->prev->lwpid,tmp->next->lwpid,tmp->lwpid); + #endif tmp->prev->next = tmp->next; tmp->next->prev = tmp->prev; - free(tmp->stack); - free(tmp); + // One killed + _lwp_count--; _lwp_flag = 1; /* jump off this task before it dies and ends up in limbo */ __lwp_pm_timer_hook(); - return(0); + // Now the free is safe because we are out of the tmp task + free(tmp->stack); + free(tmp); + // Now return OK + return(1); } @@ -176,6 +226,7 @@ _go32_dpmi_unchain_protected_mode_interrupt_vector(IRQ8, &_lwp_pm_old_handler); __dpmi_get_and_enable_virtual_interrupt_state(); signal(SIGILL, __lwp_old_handler); + __dpmi_free_ldt_descriptor(SelInDOS); _lwp_flag = 1; } @@ -185,25 +236,44 @@ { /* If it was our timer generated exception... */ disable(); - _lwp_flag = 0; - if(__djgpp_exception_state == NULL) - { - __lwp_old_handler(signum); - } - if(__djgpp_exception_state->__signum == LWP_EXCPTN) - { - memcpy(_lwp_cur->state, __djgpp_exception_state, sizeof(jmp_buf)); - /* turn off resume flag if set by the hw_int */ - _lwp_cur->state[0].__eflags = _lwp_cur->state[0].__eflags & 0xEFFFF; - _lwp_cur->prev = _lwp_cur; - _lwp_cur = _lwp_cur->next; - _lwp_flag = 1; - longjmp(_lwp_cur->state, _lwp_cur->state[0].__eax); - } - else - { - printf("Error, bailing out!\n"); - __lwp_old_handler(signum); - } + if (_lwp_flag && lwp_critical_semaphore==0 && _farpeekb(SelInDOS,OffInDOS)==0) + { + _lwp_flag = 0; + if(__djgpp_exception_state == NULL) + { + __lwp_old_handler(signum); + } + if(__djgpp_exception_state->__signum == LWP_EXCPTN) + { + memcpy(_lwp_cur->state, __djgpp_exception_state, sizeof(jmp_buf)); + /* turn off resume flag if set by the hw_int */ + _lwp_cur->state[0].__eflags = _lwp_cur->state[0].__eflags & 0xEFFFF; + //_lwp_cur->prev = _lwp_cur; + _lwp_cur = _lwp_cur->next; + _lwp_flag = 1; + longjmp(_lwp_cur->state, _lwp_cur->state[0].__eax); + } + else + { + printf("Error, bailing out!\n"); + __lwp_old_handler(signum); + } + } +} + +int lwp_inc_semaphore(void) +{ + return ++lwp_critical_semaphore; } +int lwp_dec_semaphore(void) +{ + if (lwp_critical_semaphore) + lwp_critical_semaphore--; + return lwp_critical_semaphore; +} + +int lwp_task_alive(void) +{ + return _lwp_count; +} \ No newline at end of file Patch for LWP.H: --- ..\pp\lwp.h Tue Jul 23 11:24:00 1996 +++ lwp.h Tue Jul 23 08:53:46 1996 @@ -21,3 +21,5 @@ int lwp_spawn(void (*proc)(), int stack_length); int lwp_kill(int lwpid); int lwp_getpid(); +int lwp_inc_semaphore(void); +int lwp_dec_semaphore(void); A safe test: #include "lwp.h" #include #include int spam; int bar; int snarf; int snarf2; int cont_proc1=0; int cont_proc2=0; int cont_proc3=0; int cont_proc4=0; void proc1(void) { while(!lwkbhit()) { cont_proc1++; } cont_proc1=0; lwp_kill(lwp_getpid()); } void proc2(void) { while(!lwkbhit()) { cont_proc2++; } cont_proc2=0; lwp_kill(lwp_getpid()); } void proc3(void) { while(!lwkbhit()) { cont_proc3++; } cont_proc3=0; lwp_kill(lwp_getpid()); } void proc4(void) { while(!lwkbhit() && cont_proc4<100000) { cont_proc4++; } cont_proc4=0; lwp_kill(lwp_getpid()); } main() { lwp_init(); lwp_spawn(proc1, 65536); lwp_spawn(proc2, 65536); lwp_spawn(proc3, 65536); lwp_spawn(proc4, 65536); while(!kbhit()) { printf("%d %d %d %d\n",cont_proc1,cont_proc2,cont_proc3,cont_proc4); } // Wait for all killed: while (cont_proc1 || cont_proc2 || cont_proc3 || cont_proc4) printf("Waiting for the rest of the tasks\n"); getch(); lwp_deinit(); } bye SET. ******************************************************************************** Salvador Eduardo Tropea (SET) - salvador AT inti DOT edu DOT ar Work: INTI (National Institute of Industrial Technology) Sector: ICE (Electronic Control & Instrumentation) Post (Home): Curapaligue 2124 - Caseros (1678)- Buenos Aires - Argentina