Loading...
launch-cache/update_dyld_shared_cache.cpp dyld-95.3 dyld-97.1
--- dyld/dyld-95.3/launch-cache/update_dyld_shared_cache.cpp
+++ dyld/dyld-97.1/launch-cache/update_dyld_shared_cache.cpp
@@ -31,9 +31,11 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <fcntl.h>
+#include <signal.h>
 #include <errno.h>
 #include <sys/uio.h>
 #include <unistd.h>
+#include <dirent.h>
 #include <sys/param.h>
 #include <sys/sysctl.h>
 #include <sys/resource.h>
@@ -390,7 +392,7 @@
 {
 public:
 							SharedCache(ArchGraph* graph, bool alphaSort, uint64_t dyldBaseAddress);
-	bool					update(const char* rootPath, const char* cacheDir, bool force, bool optimize, int archIndex, int archCount);
+	bool					update(const char* rootPath, const char* cacheDir, bool force, bool optimize, bool deleteExistingFirst, int archIndex, int archCount);
 	static const char*		filename(bool optimized);
 
 private:
@@ -440,7 +442,6 @@
 	std::vector<LayoutInfo>				fDylibs;
 	std::vector<shared_file_mapping_np>	fMappings;
 	uint32_t							fHeaderSize;
-	uint8_t*							fMappedCacheFile;
 	uint64_t							fDyldBaseAddress;
 	uint64_t							fLinkEditsTotalUnoptimizedSize;
 	uint64_t							fLinkEditsStartAddress;
@@ -1195,8 +1196,21 @@
 }
 
 
+static const char* sCleanupFile = NULL;
+static void cleanup(int sig)
+{
+	::signal(sig, SIG_DFL);
+	if ( sCleanupFile != NULL )
+		::unlink(sCleanupFile);
+	//if ( verbose )
+	//	fprintf(stderr, "update_dyld_shared_cache: deleting temp file in response to a signal\n");
+	if ( sig == SIGINT )
+		::exit(1);
+}
+
+
 template <typename A>
-bool SharedCache<A>::update(const char* rootPath, const char* cacheDir, bool force, bool optimize, int archIndex, int archCount)
+bool SharedCache<A>::update(const char* rootPath, const char* cacheDir, bool force, bool optimize, bool deleteExistingFirst, int archIndex, int archCount)
 {
 	bool didUpdate = false;
 	char cachePath[1024];
@@ -1213,29 +1227,28 @@
 			fprintf(stderr, "update_dyld_shared_cache: warning, empty cache not generated for arch %s\n", archName());
 			return false;
 		}
+		// delete existing cache while building the new one
+		// this is a flag to dyld to stop pinging update_dyld_shared_cache
+		if ( deleteExistingFirst )
+			::unlink(cachePath);
+		uint8_t* inMemoryCache = NULL;
+		uint32_t allocatedCacheSize = 0;
 		char tempCachePath[strlen(cachePath)+16];
 		sprintf(tempCachePath, "%s.tmp%u", cachePath, getpid());
 		try {
-			int fd = ::open(tempCachePath, O_CREAT | O_RDWR | O_TRUNC, 0644);	
-			if ( fd == -1 )
-				throwf("can't create temp file %s, errnor=%d", tempCachePath, errno);
-				
-			// try to allocate whole cache file contiguously
+			// allocate a memory block to hold cache
 			uint32_t cacheFileSize = 0;
 			for(std::vector<shared_file_mapping_np>::iterator it = fMappings.begin(); it != fMappings.end(); ++it) {
 				uint32_t end = it->sfm_file_offset + it->sfm_size;
 				if ( end > cacheFileSize )
 					cacheFileSize = end;
 			}
-			fstore_t fcntlSpec = { F_ALLOCATECONTIG|F_ALLOCATEALL, F_PEOFPOSMODE, 0, cacheFileSize, 0 };
-			fcntl(fd, F_PREALLOCATE, &fcntlSpec);
-  
-			// fill in cache header memory buffer
-			uint8_t buffer[pageAlign(fHeaderSize)];
-			bzero(buffer, sizeof(buffer));
+			if ( vm_allocate(mach_task_self(), (vm_address_t*)(&inMemoryCache), cacheFileSize, VM_FLAGS_ANYWHERE) != KERN_SUCCESS )
+				throwf("can't vm_allocate cache of size %u", cacheFileSize);
+			allocatedCacheSize = cacheFileSize;
 			
 			// fill in header
-			dyldCacheHeader<E>* header = (dyldCacheHeader<E>*)buffer;
+			dyldCacheHeader<E>* header = (dyldCacheHeader<E>*)inMemoryCache;
 			char temp[16];
 			strcpy(temp, "dyld_v1        ");
 			strcpy(&temp[15-strlen(archName())], archName());
@@ -1250,7 +1263,7 @@
 			//header->set_dependenciesCount(fDependencyPool.size());
 			
 			// fill in mappings
-			dyldCacheFileMapping<E>* mapping = (dyldCacheFileMapping<E>*)&buffer[sizeof(dyldCacheHeader<E>)];
+			dyldCacheFileMapping<E>* mapping = (dyldCacheFileMapping<E>*)&inMemoryCache[sizeof(dyldCacheHeader<E>)];
 			for(std::vector<shared_file_mapping_np>::iterator it = fMappings.begin(); it != fMappings.end(); ++it) {
 				if ( verbose )
 					fprintf(stderr, "update_dyld_shared_cache: cache mappings: address=0x%0llX, size=0x%0llX, fileOffset=0x%0llX, prot=0x%X\n", 
@@ -1274,23 +1287,7 @@
 				++image;
 			}
 						
-			// write whole header to disk
-			pwrite(fd, buffer, sizeof(buffer), 0);
-			
-			// allocate copy buffer
-			const uint64_t kCopyBufferSize = 256*1024;
-			uint8_t* copyBuffer;
-			vm_address_t addr = 0;
-			if ( vm_allocate(mach_task_self(), &addr, kCopyBufferSize, VM_FLAGS_ANYWHERE) == KERN_SUCCESS )
-				copyBuffer = (uint8_t*)addr;
-			else
-				throw "can't allcoate copy buffer";
-
-			// make zero-fill buffer
-			uint8_t zerofill[4096];
-			bzero(zerofill, sizeof(zerofill));
-
-			// write each segment to cache file
+			// copy each segment to cache buffer
 			int dylibIndex = 0;
 			for(typename std::vector<LayoutInfo>::const_iterator it = fDylibs.begin(); it != fDylibs.end(); ++it, ++dylibIndex) {
 				const char* path = it->layout->getFilePath();
@@ -1299,9 +1296,15 @@
 					throwf("can't open file %s, errnor=%d", it->layout->getID().name, errno);
 				// mark source as "don't cache"
 				(void)fcntl(src, F_NOCACHE, 1);
+				// verify file has not changed since dependency analysis
+				struct stat stat_buf;
+				if ( fstat(src, &stat_buf) == -1)
+					throwf("can't stat open file %s, errno=%d", path, errno);
+				if ( (it->layout->getInode() != stat_buf.st_ino) || (it->layout->getLastModTime() != stat_buf.st_mtime) )
+					throwf("aborting because OS dylib modified during cache creation: %s", path);
 
 				if ( verbose )
-					fprintf(stderr, "update_prebinding: copying %s to cache\n", it->layout->getID().name);
+					fprintf(stderr, "update_dyld_shared_cache: copying %s to cache\n", it->layout->getID().name);
 				try {
 					const std::vector<MachOLayoutAbstraction::Segment>& segs = it->layout->getSegments();
 					for (int i=0; i < segs.size(); ++i) {
@@ -1312,21 +1315,31 @@
 							const uint64_t segmentSrcStartOffset = it->layout->getOffsetInUniversalFile()+seg.fileOffset();
 							const uint64_t segmentSize = seg.fileSize();
 							const uint64_t segmentDstStartOffset = cacheFileOffsetForAddress(seg.newAddress());
-							for(uint64_t copiedAmount=0; copiedAmount < segmentSize; copiedAmount += kCopyBufferSize) {
-								uint64_t amount = std::min(segmentSize-copiedAmount, kCopyBufferSize);
-								//fprintf(stderr, "copy 0x%08llX bytes at offset 0x%08llX for segment %s in %s to cache offset 0x%08llX\n", 
-								//		amount, segmentSrcStartOffset+copiedAmount, seg.name(), it->layout->getID().name, segmentDstStartOffset+copiedAmount);
-								if ( ::pread(src, copyBuffer, amount, segmentSrcStartOffset+copiedAmount) != amount )
+							ssize_t readResult = ::pread(src, &inMemoryCache[segmentDstStartOffset], segmentSize, segmentSrcStartOffset);
+							if ( readResult != segmentSize ) 
+								if ( readResult == -1 )
 									throwf("read failure copying dylib errno=%d for %s", errno, it->layout->getID().name);
-								if ( ::pwrite(fd, copyBuffer, amount, segmentDstStartOffset+copiedAmount) != amount )
-									throwf("write failure copying dylib errno=%d for %s", errno, it->layout->getID().name);
-							}
-							if ( seg.size() > seg.fileSize() ) {
-								// write zero-filled area
-								for(uint64_t copiedAmount=seg.fileSize(); copiedAmount < seg.size(); copiedAmount += sizeof(zerofill)) {
-									uint64_t amount = std::min(seg.size()-copiedAmount, (uint64_t)(sizeof(zerofill)));
-									if ( ::pwrite(fd, zerofill, amount, segmentDstStartOffset+copiedAmount) != amount )
-										throwf("write failure copying dylib errno=%d for %s", errno, it->layout->getID().name);
+								else
+									throwf("read failure copying dylib. Read of %lld bytes at file offset %lld returned %ld for %s", 
+											segmentSize, segmentSrcStartOffset, readResult, it->layout->getID().name);
+							// verify __TEXT segment has no zeroed out pages
+							if ( strcmp(seg.name(), "__TEXT") == 0 ) {
+								// only scan first 128KB.  Some OS dylibs have zero filled TEXT pages later in __const...
+								int scanEnd = segmentSize;
+								if ( scanEnd > 0x20000 )
+									scanEnd = 0x20000;
+								for (int pageOffset = 0; pageOffset < scanEnd; pageOffset += 4096) {
+									const uint32_t* page = (uint32_t*)(&inMemoryCache[segmentDstStartOffset+pageOffset]);
+									bool foundNonZero = false;
+									for(int p=0; p < 1024; ++p) {
+										if ( page[p] != 0 ) {
+											//fprintf(stderr, "found non-zero at pageOffset=0x%08X, p=0x%08X in memory=%p for %s\n", pageOffset, p, page, it->layout->getID().name);
+											foundNonZero = true;
+											break;
+										}
+									}
+									if ( !foundNonZero )
+										throwf("suspected bad read. Found __TEXT segment page at offset 0x%08X that is all zeros for %s in %s", pageOffset, archName(), it->layout->getID().name);
 								}
 							}
 						}
@@ -1337,26 +1350,14 @@
 				}
 				::close(src);
 			}
-			
-			// free copy buffer
-			vm_deallocate(mach_task_self(), addr, kCopyBufferSize);
-			
-			// map cache file
-			fMappedCacheFile = (uint8_t*)mmap(NULL, cacheFileSize, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
-			if ( fMappedCacheFile == (uint8_t*)(-1) )
-				throw "can't mmap cache file";
-
-			// close cache file
-			::fsync(fd);
-			::close(fd);
-
+						
 			// set mapped address for each segment
 			for(typename std::vector<LayoutInfo>::const_iterator it = fDylibs.begin(); it != fDylibs.end(); ++it) {
 				std::vector<MachOLayoutAbstraction::Segment>& segs = ((MachOLayoutAbstraction*)(it->layout))->getSegments();
 				for (int i=0; i < segs.size(); ++i) {
 					MachOLayoutAbstraction::Segment& seg = segs[i];
 					if ( seg.size() > 0 )
-						seg.setMappedAddress(fMappedCacheFile + cacheFileOffsetForAddress(seg.newAddress()));
+						seg.setMappedAddress(inMemoryCache + cacheFileOffsetForAddress(seg.newAddress()));
 					//fprintf(stderr, "%s at %p to %p for %s\n", seg.name(), seg.mappedAddress(), (char*)seg.mappedAddress()+ seg.size(), it->layout->getID().name);
 				}
 			}
@@ -1377,11 +1378,11 @@
 			// merge/optimize all LINKEDIT segments
 			if ( optimize ) {
 				//fprintf(stderr, "update_dyld_shared_cache: original cache file size %uMB\n", cacheFileSize/(1024*1024));
-				cacheFileSize = (this->optimizeLINKEDIT() - fMappedCacheFile);
+				cacheFileSize = (this->optimizeLINKEDIT() - inMemoryCache);
 				//fprintf(stderr, "update_dyld_shared_cache: optimized cache file size %uMB\n", cacheFileSize/(1024*1024));
 				// update header to reduce mapping size
-				dyldCacheHeader<E>* cacheHeader = (dyldCacheHeader<E>*)fMappedCacheFile;
-				dyldCacheFileMapping<E>* mappings = (dyldCacheFileMapping<E>*)&fMappedCacheFile[sizeof(dyldCacheHeader<E>)];
+				dyldCacheHeader<E>* cacheHeader = (dyldCacheHeader<E>*)inMemoryCache;
+				dyldCacheFileMapping<E>* mappings = (dyldCacheFileMapping<E>*)&inMemoryCache[sizeof(dyldCacheHeader<E>)];
 				dyldCacheFileMapping<E>* lastMapping = &mappings[cacheHeader->mappingCount()-1];
 				lastMapping->set_size(cacheFileSize-lastMapping->file_offset());
 				// update fMappings so .map file will print correctly
@@ -1420,33 +1421,53 @@
 			for(typename std::vector<Binder<A>*>::iterator it = binders.begin(); it != binders.end(); ++it) {
 				delete *it;
 			}
-		
-			// close mapping
-			int result = ::msync(fMappedCacheFile, cacheFileSize, MS_SYNC);
-			if ( result != 0 )
-				throw "error syncing cache file";
-			result = ::munmap(fMappedCacheFile, cacheFileSize);
-			if ( result != 0 )
-				throw "error unmapping cache file";
+	
+			// install signal handlers to delete temp file if program is killed 
+			sCleanupFile = tempCachePath;
+			::signal(SIGINT, cleanup);
+			::signal(SIGBUS, cleanup);
+			::signal(SIGSEGV, cleanup);
 			
-			// cut back cache file to match optmized size
-			if ( optimize ) {
-				if ( ::truncate(tempCachePath, cacheFileSize) != 0 )
-					throw "error truncating cache file";
-			}
+			// create temp file for cache
+			int fd = ::open(tempCachePath, O_CREAT | O_RDWR | O_TRUNC, 0644);	
+			if ( fd == -1 )
+				throwf("can't create temp file %s, errnor=%d", tempCachePath, errno);
+				
+			// try to allocate whole cache file contiguously
+			fstore_t fcntlSpec = { F_ALLOCATECONTIG|F_ALLOCATEALL, F_PEOFPOSMODE, 0, cacheFileSize, 0 };
+			::fcntl(fd, F_PREALLOCATE, &fcntlSpec);
+
+			// write out cache file
+			if ( verbose )
+				fprintf(stderr, "update_dyld_shared_cache: writing cache to disk\n");
+			if ( ::pwrite(fd, inMemoryCache, cacheFileSize, 0) != cacheFileSize )
+				throwf("write() failure creating cache file, errno=%d", errno);
 			
-			// commit 
-			::sync();
-			// flush everything to disk, otherwise if kernel panics before the cache file is completely written to disk
-			// then next reboot will use a corrupted cache and die
+			// flush to disk and close
+			int result = ::fcntl(fd, F_FULLFSYNC, NULL);
+			if ( result == -1 ) 
+				fprintf(stderr, "update_dyld_shared_cache: warning, fcntl(F_FULLFSYNC) failed with errno=%d for %s\n", errno, tempCachePath);
+			result = ::close(fd);
+			if ( result != 0 ) 
+				fprintf(stderr, "update_dyld_shared_cache: warning, close() failed with errno=%d for %s\n", errno, tempCachePath);
+			
+			// atomically swap in new cache file, do this after F_FULLFSYNC
 			result = ::rename(tempCachePath, cachePath);
 			if ( result != 0 ) 
 				throwf("can't swap newly create dyld shared cache file: rename(%s,%s) returned errno=%d", tempCachePath, cachePath, errno);
+				
 			// flush everything to disk to assure rename() gets recorded
 			::sync();
 			didUpdate = true;
+			
+			// restore default signal handlers
+			::signal(SIGINT, SIG_DFL);
+			::signal(SIGBUS, SIG_DFL);
+			::signal(SIGSEGV, SIG_DFL);
 
 			// generate human readable "map" file that shows the layout of the cache file
+			if ( verbose )
+				fprintf(stderr, "update_dyld_shared_cache: writing .map file to disk\n");
 			sprintf(tempCachePath, "%s.map", cachePath);// re-use path buffer
 			FILE* fmap = ::fopen(tempCachePath, "w");	
 			if ( fmap == NULL ) {
@@ -1484,10 +1505,17 @@
 				}
 				fclose(fmap);
 			}
+			
+			// free in memory cache
+			vm_deallocate(mach_task_self(), (vm_address_t)inMemoryCache, allocatedCacheSize);
+			inMemoryCache = NULL;
 		}
 		catch (...){
-			// remove temp cache
+			// remove temp cache file
 			::unlink(tempCachePath);
+			// remove in memory cache
+			if ( inMemoryCache != NULL ) 
+				vm_deallocate(mach_task_self(), (vm_address_t)inMemoryCache, allocatedCacheSize);
 			throw;
 		}
 	}
@@ -1617,9 +1645,51 @@
 }
 
 
+// If the 10.5.0 version of update_dyld_shared_cache was killed or crashed, it 
+// could leave large half written cache files laying around.  The function deletes
+// those files.  To prevent the deletion of tmp files being created by another
+// copy of update_dyld_shared_cache, it only deletes the temp cache file if its 
+// creation time was before the last restart of this machine.
+static void deleteOrphanTempCacheFiles()
+{
+	DIR* dir = ::opendir(DYLD_SHARED_CACHE_DIR);
+	if ( dir != NULL ) {
+		std::vector<const char*> filesToDelete;
+		for (dirent* entry = ::readdir(dir); entry != NULL; entry = ::readdir(dir)) {
+			if ( entry->d_type == DT_REG ) {
+				// only look at files with .tmp in name
+				if ( strstr(entry->d_name, ".tmp") != NULL ) {
+					char fullPath[strlen(DYLD_SHARED_CACHE_DIR)+entry->d_namlen+2];
+					strcpy(fullPath, DYLD_SHARED_CACHE_DIR);
+					strcat(fullPath, "/");
+					strcat(fullPath, entry->d_name);
+					struct stat tmpFileStatInfo;
+					if ( stat(fullPath, &tmpFileStatInfo) != -1 ) {
+						int mib[2] = {CTL_KERN, KERN_BOOTTIME};
+						struct timeval boottime;
+						size_t size = sizeof(boottime);
+						if ( (sysctl(mib, 2, &boottime, &size, NULL, 0) != -1) && (boottime.tv_sec != 0) ) {	
+							// make sure this file is older than the boot time of this machine
+							if ( tmpFileStatInfo.st_mtime < boottime.tv_sec ) {
+								filesToDelete.push_back(strdup(fullPath));
+							}
+						}
+					}
+				}
+			}
+		}
+		::closedir(dir);
+		for(std::vector<const char*>::iterator it = filesToDelete.begin(); it != filesToDelete.end(); ++it) {
+			fprintf(stderr, "update_dyld_shared_cache: deleting old temp cache file: %s\n", *it);
+			::unlink(*it);
+		}
+	}
+}
+
+
 
 static bool updateSharedeCacheFile(const char* rootPath, const char* cacheDir, const std::set<cpu_type_t>& onlyArchs, 
-									bool force, bool alphaSort, bool optimize)
+									bool force, bool alphaSort, bool optimize, bool deleteExistingFirst)
 {
 	bool didUpdate = false;
 	// get dyld load address info
@@ -1638,32 +1708,35 @@
 					SharedCache<ppc> cache(ArchGraph::getArch(*a), alphaSort, dyldBaseAddress);
 		#if __i386__
 					// <rdar://problem/5217377> Rosetta does not work with optimized dyld shared cache
-					didUpdate |= cache.update(rootPath, cacheDir, force, false, index, archCount);
+					didUpdate |= cache.update(rootPath, cacheDir, force, false, deleteExistingFirst, index, archCount);
 		#else
-					didUpdate |= cache.update(rootPath, cacheDir, force, optimize, index, archCount);
+					didUpdate |= cache.update(rootPath, cacheDir, force, optimize, deleteExistingFirst, index, archCount);
 		#endif
 				}
 				break;
 			case CPU_TYPE_POWERPC64:
 				{
 					SharedCache<ppc64> cache(ArchGraph::getArch(*a), alphaSort, dyldBaseAddress);
-					didUpdate |= cache.update(rootPath, cacheDir, force, optimize, index, archCount);
+					didUpdate |= cache.update(rootPath, cacheDir, force, optimize, deleteExistingFirst, index, archCount);
 				}
 				break;
 			case CPU_TYPE_I386:
 				{
 					SharedCache<x86> cache(ArchGraph::getArch(*a), alphaSort, dyldBaseAddress);
-					didUpdate |= cache.update(rootPath, cacheDir, force, optimize, index, archCount);
+					didUpdate |= cache.update(rootPath, cacheDir, force, optimize, deleteExistingFirst, index, archCount);
 				}
 				break;
 			case CPU_TYPE_X86_64:
 				{
 					SharedCache<x86_64> cache(ArchGraph::getArch(*a), alphaSort, dyldBaseAddress);
-					didUpdate |= cache.update(rootPath, cacheDir, force, optimize, index, archCount);
+					didUpdate |= cache.update(rootPath, cacheDir, force, optimize, deleteExistingFirst, index, archCount);
 				}
 				break;
 		}
 	}
+	
+	deleteOrphanTempCacheFiles();
+	
 	return didUpdate;
 }
 
@@ -1673,31 +1746,42 @@
 	fprintf(stderr, "update_dyld_shared_cache [-force] [-root dir] [-arch arch] [-debug]\n");
 }
 
+// flag so that we only update cache once per invocation
+static bool doNothingAndDrainQueue = false;
+
+static kern_return_t do_update_cache(cpu_type_t arch, bool deleteExistingCacheFileFirst)
+{
+	if ( !doNothingAndDrainQueue ) {
+		std::set<cpu_type_t> onlyArchs;
+		onlyArchs.insert(arch);
+		try {
+			scanForSharedDylibs("", "/var/db/dyld/shared_region_roots/", onlyArchs);
+			if ( updateSharedeCacheFile("", DYLD_SHARED_CACHE_DIR, onlyArchs, false, false, true, deleteExistingCacheFileFirst) )
+				fprintf(stderr, "update_dyld_shared_cache[%u] regenerated cache for arch=%s\n", getpid(), ArchGraph::archName(arch));
+		}
+		catch (const char* msg) {
+			fprintf(stderr, "update_dyld_shared_cache[%u] for arch=%s failed: %s\n", getpid(), ArchGraph::archName(arch), msg);
+			return KERN_FAILURE;
+		}
+		// <rdar://problem/6378354> only build one cache file per life of process
+		doNothingAndDrainQueue = true;
+	}
+	return KERN_SUCCESS;
+}
+
+
 
 kern_return_t do_dyld_shared_cache_missing(mach_port_t dyld_port, cpu_type_t arch)
 {
-	std::set<cpu_type_t> onlyArchs;
-	onlyArchs.insert(arch);
-	try {
-		scanForSharedDylibs("", "/var/db/dyld/shared_region_roots/", onlyArchs);
-		if ( updateSharedeCacheFile("", DYLD_SHARED_CACHE_DIR, onlyArchs, false, false, true) )
-			fprintf(stderr, "update_dyld_shared_cache[%u] regenerated cache for arch=%s\n", getpid(), ArchGraph::archName(arch));
-	}
-	catch (const char* msg) {
-		fprintf(stderr, "update_dyld_shared_cache[%u] for arch=%s failed: %s\n", getpid(), ArchGraph::archName(arch), msg);
-		return KERN_FAILURE;
-	}
-	return KERN_SUCCESS;
+	return do_update_cache(arch, false);
 }
 
 
 kern_return_t do_dyld_shared_cache_out_of_date(mach_port_t dyld_port, cpu_type_t arch)
 {
-	// reduce priority of this process so it only runs at the lowest priority 
-	setpriority(PRIO_PROCESS, 0, PRIO_MAX);
-	
-	// and then rebuild cache
-	return do_dyld_shared_cache_missing(dyld_port, arch);
+	// If cache exists but is out of date, delete the file while building the new one.
+	// This will stop dyld from pinging update_dyld_share_cache while the cache is being built.
+	return do_update_cache(arch, true);
 }
 
 
@@ -1706,12 +1790,18 @@
 	mach_port_t mp;
 	if ( bootstrap_check_in(bootstrap_port, "com.apple.dyld", &mp) == KERN_SUCCESS ) {
 		// started by launchd
-		// Just process one message and quit
 		mach_msg_size_t mxmsgsz = sizeof(union __RequestUnion__do_dyld_server_subsystem) + MAX_TRAILER_SIZE;
-		mach_msg_server_once(dyld_server_server, mxmsgsz, mp, MACH_RCV_TIMEOUT);
-		// The problem with staying alive and processing messages is that the rest of this 
-		// tool leaks mapped memory and file descriptors.  Quiting will clean that up.
-		// <rdar://problem/5392427> 9A516 - Keep getting disk full errors
+		doNothingAndDrainQueue = false;
+		while ( mach_msg_server(dyld_server_server, mxmsgsz, mp, MACH_RCV_TIMEOUT) == KERN_SUCCESS ) {
+			// keep processing messages
+			doNothingAndDrainQueue = true;
+			// but set flag so work is no longer done.
+			// This is because the rest of the tool leaks and processing more than once
+			// can hog system resources: <rdar://problem/5392427> 9A516 - Keep getting disk full errors
+			// We drain the queue of messages because there is usually are a couple of duplicate messages.
+			// It is ok to miss some messages.  If the cache is out of date or missing, some new process
+			// will discover it and send another message.  
+		}
 		return 0;
 	}
 	else {
@@ -1811,7 +1901,7 @@
 			
 			// build list of shared dylibs
 			scanForSharedDylibs(rootPath, "/var/db/dyld/shared_region_roots/", onlyArchs);
-			updateSharedeCacheFile(rootPath, DYLD_SHARED_CACHE_DIR, onlyArchs, force, alphaSort, optimize);
+			updateSharedeCacheFile(rootPath, DYLD_SHARED_CACHE_DIR, onlyArchs, force, alphaSort, optimize, false);
 			
 			// To make a universal bootable image with dyld caches,
 			// build the rosetta cache and symlink ppc to point to it.