Avoid creating too many threads by limiting them to 250. Work around a problem in ext2 where this would case a deadlock since we would sometimes not create the thread needed for reading the superblock... --- libports/manage-multithread.c.orig 2005-08-10 13:38:18.000000000 +0200 +++ libports/manage-multithread.c 2005-08-10 13:34:30.000000000 +0200 @@ -23,6 +23,19 @@ #include #include #include +#include /* For sleep() */ + +#define LP_DEBUG 0 + +#if LP_DEBUG +#include /* For printf() */ +#endif + +#define THREAD_MAX 250 /* Maximum number of threads */ +#define THREAD_DELAY 64 /* Number of threads created as needed + without delay */ +#define DELAY 2 /* Time to sleep() each delayed thread + (in seconds) */ void ports_manage_port_operations_multithread (struct port_bucket *bucket, @@ -43,6 +56,7 @@ { int spawn = 0; int status; + int type = 0; /* 0 = standard, 1 = master, 2 = delayed */ struct port_info *pi; struct rpc_info link; register mig_reply_header_t *outp = (mig_reply_header_t *) outheadp; @@ -59,8 +73,11 @@ spin_lock (&lock); assert (nreqthreads); nreqthreads--; - if (nreqthreads == 0) - spawn = 1; + if (nreqthreads == 0 && totalthreads <= THREAD_MAX) { + spawn = 1; + if (totalthreads >= THREAD_DELAY) + type = 2; + } spin_unlock (&lock); if (spawn) @@ -69,7 +86,8 @@ totalthreads++; nreqthreads++; spin_unlock (&lock); - cthread_detach (cthread_fork ((cthread_fn_t) thread_function, 0)); + cthread_detach (cthread_fork ((cthread_fn_t) thread_function, + (any_t)(intptr_t) type)); } /* Fill in default response. */ @@ -117,15 +135,31 @@ } int - thread_function (int master) + thread_function (int type) { int timeout; error_t err; - + + if (type == 2) { +#if LP_DEBUG + printf("libports: delayed thread number: %d || ", totalthreads); + fflush(stdout); +#endif + sleep(DELAY); /* Take a little break */ +#if LP_DEBUG + printf("libports: delayed thread running (%d)\n", totalthreads); + fflush(stdout); +#endif + } +#if LP_DEBUG + else { + printf("libports: new thread without delay running\n"); + } +#endif if (hook) (*hook) (); - if (master) + if (type == 1) timeout = global_timeout; else timeout = thread_timeout; @@ -138,7 +172,7 @@ timeout); while (err != MACH_RCV_TIMED_OUT); - if (master) + if (type == 1) { spin_lock (&lock); if (totalthreads != 1) --- ext2fs/hyper.c 2008-03-10 01:14:16.643969000 +0000 +++ ext2fs/hyper.c 2008-03-01 23:41:53.227511000 +0000 @@ -55,17 +55,22 @@ static int ext2fs_clean; /* fs clean before we started writing? */ +struct ext2_super_block *__sblock = NULL; void get_hypermetadata (void) { error_t err; size_t read; + static struct ext2_super_block _sblock; assert (! sblock); err = store_read (store, SBLOCK_OFFS >> store->log2_block_size, - SBLOCK_SIZE, (void **)&sblock, &read); + SBLOCK_SIZE, (void **)&__sblock, &read); if (err || read != SBLOCK_SIZE) ext2_panic ("Cannot read hypermetadata"); + + sblock = &_sblock; + *sblock = *__sblock; if (sblock->s_magic != EXT2_SUPER_MAGIC #ifdef EXT2FS_PRE_02B_COMPAT @@ -159,18 +164,18 @@ if (zeroblock == 0) zeroblock = (vm_address_t) mmap (0, block_size, PROT_READ, MAP_ANON, 0, 0); - munmap (sblock, SBLOCK_SIZE); - sblock = NULL; + munmap (__sblock, SBLOCK_SIZE); + __sblock = NULL; } void map_hypermetadata (void) { - sblock = (struct ext2_super_block *) boffs_ptr (SBLOCK_OFFS); + __sblock = (struct ext2_super_block *) boffs_ptr (SBLOCK_OFFS); /* Cache a convenient pointer to the block group descriptors for allocation. These are stored in the filesystem blocks following the superblock. */ - group_desc_image = (struct ext2_group_desc *) bptr (bptr_block (sblock) + 1); + group_desc_image = (struct ext2_group_desc *) bptr (bptr_block (__sblock) + 1); } error_t @@ -193,8 +198,9 @@ if (sblock_dirty) { sblock_dirty = 0; - disk_cache_block_ref_ptr (sblock); - record_global_poke (sblock); + *__sblock = *sblock; + disk_cache_block_ref_ptr (__sblock); + record_global_poke (__sblock); } sync_global (wait);