From: sandmann AT clio DOT rice DOT edu (Charles Sandmann) Message-Id: <10108190425.AA12230@clio.rice.edu> Subject: Selector exhaustion code update To: djgpp-workers AT delorie DOT com (DJGPP developers) Date: Sat, 18 Aug 2001 23:25:18 -0500 (CDT) X-Mailer: ELM [version 2.5 PL2] Mime-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Transfer-Encoding: 7bit Reply-To: djgpp-workers AT delorie DOT com Included below is my version of the selector code based on Andris code and my test code. In the initialization section it tests which selector characteristics change on a selector allocation. Option 1, LAR, is Andris' discovery. Option 2 is how I've found to do the same on Windows NT/2K/XP. In both cases I scan a relatively small area of the selector space, so the number of calls will not be a performance issue. A map is kept for the working area. If nothing seems to be able to detect the change in selector status, we do nothing (Option 3, blindly deallocate, is left in the cleanup code but it cannot be actived currently.) The code below is willing to leak a few selectors if the default scan zone is not large enough - it will then increase this area. For all images compiled with this code it never happens since we only leak 5 for each spawn. If you have a nested non-cvs image, you might need to loose a few and then expand (so building make alone should work). Comments? Since the new code is rather conservative, I didn't see a reason to disable it. *** dosexec.c_ Sat Jul 28 17:54:04 2001 --- test3.c Sat Aug 18 23:11:00 2001 *************** size_t __cmdline_str_len = sizeof(__cmdl *** 157,163 **** if LFN is 2, there is a possiblity that the contents of the transfer buffer will be overrun! */ static int ! direct_exec_tail(const char *program, const char *args, char * const envp[], const char *proxy, int lfn, const char *cmdline_var) { --- 157,163 ---- if LFN is 2, there is a possiblity that the contents of the transfer buffer will be overrun! */ static int ! direct_exec_tail_1 (const char *program, const char *args, char * const envp[], const char *proxy, int lfn, const char *cmdline_var) { *************** direct_exec_tail(const char *program, co *** 413,418 **** --- 413,532 ---- return r.h.al; /* AL holds the child exit code */ } + static int direct_exec_tail (const char *program, const char *args, + char * const envp[], const char *proxy, int lfn, + const char *cmdline_var) + { + int i, ret; + int sel1, sel2; + static char first_call = 1; + static char workaround_descriptor_leaks = 0; + static unsigned char larbyte = 0; + static int how_deep = 12; + static char *desc_map = NULL; + + sel1 = sel2 = 0; /* Warnings */ + + if (first_call) + { + int flags; + char dpmi_vendor[128]; + unsigned char desc_buf1[8], desc_buf2[8]; + + /* Disable descriptors leak workaround when CWSDPMI is being used */ + /* since not needed. Does not work with CWSDPMI versions before */ + /* r5 as corresponding DPMI call is supported beginning with v5. */ + + ret = __dpmi_get_capabilities(&flags,dpmi_vendor); + if (ret == 0 && strcmp(dpmi_vendor+2,"CWSDPMI") == 0) + workaround_descriptor_leaks = 0; + else { + sel1 = __dpmi_allocate_ldt_descriptors(1); + larbyte = 0xf0 & __dpmi_get_descriptor_access_rights(sel1); + __dpmi_get_descriptor(sel1, &desc_buf1); + __dpmi_free_ldt_descriptor(sel1); + flags = __dpmi_get_descriptor_access_rights(sel1); /* freed */ + + if (larbyte != (flags & 0xf0)) { /* present+ring+sys changed */ + workaround_descriptor_leaks = 1; + + } else { /* Win NT/2K/XP lie about lar */ + larbyte = desc_buf1[5] & 0xf0; + ret = __dpmi_get_descriptor(sel1, &desc_buf2); + if (ret == -1 || (larbyte != (desc_buf2[5] & 0xf0))) { + workaround_descriptor_leaks = 2; + } else + workaround_descriptor_leaks = 0; /* Don't do anything */ + } + } + if (workaround_descriptor_leaks) + desc_map = (char *)malloc(how_deep); + first_call = 0; + } + + if (workaround_descriptor_leaks) /* Create the unused map */ + { + unsigned char desc_buf[8]; + char * map = desc_map; + + sel1 = __dpmi_allocate_ldt_descriptors(1); + if(sel1 < _dos_ds) { /* Failure -1 also matches */ + sel1 = _dos_ds; + *map++ = 0; /* don't free it */ + } else + *map++ = 1; /* sel1 always released */ + sel2 = sel1 + 8 * how_deep - 8; + + if (workaround_descriptor_leaks == 1) { + for (i=sel1+8; i<=sel2; i+=8) + *map++ = (__dpmi_get_descriptor_access_rights(i) & 0xf0) != larbyte; + + } else if (workaround_descriptor_leaks == 2) { + for (i=sel1+8; i<=sel2; i+=8) /* Optimize here using lar */ + if (__dpmi_get_descriptor(i, &desc_buf) == -1) + *map++ = 1; + else + *map++ = (desc_buf[5] & 0xf0) != larbyte; + } + } + + ret = direct_exec_tail_1 ( program, args, envp, proxy, lfn, cmdline_var ); + + if (workaround_descriptor_leaks) /* Free the unused map */ + { + int endsel; + char * map; + + map = desc_map + how_deep; + + endsel = __dpmi_allocate_ldt_descriptors(1); + __dpmi_free_ldt_descriptor (endsel); + + if (workaround_descriptor_leaks == 1) { + for (i=sel2; i>=sel1; i-=8) + if (*--map) + if ((__dpmi_get_descriptor_access_rights(i) & 0xf0) == larbyte) + __dpmi_free_ldt_descriptor(i); + + } else if (workaround_descriptor_leaks == 2) { + for (i=sel2; i>=sel1; i-=8) + if (*--map) /* No checking, doing faster */ + __dpmi_free_ldt_descriptor(i); + + } else if (workaround_descriptor_leaks == 3) { + for (i=endsel-8; i>=sel1; i-=8) + __dpmi_free_ldt_descriptor(i); + } + + if (endsel > sel2) { + free(desc_map); + how_deep = (endsel - sel1) / 4; /* Twice what's needed */ + desc_map = (char *)malloc(how_deep); + } + } + return ret; + } + int _dos_exec(const char *program, const char *args, char * const envp[], const char *cmdline_var)