From owner-freebsd-current@FreeBSD.ORG Thu Mar 6 01:12:58 2008 Return-Path: Delivered-To: current@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 8163F106566B for ; Thu, 6 Mar 2008 01:12:58 +0000 (UTC) (envelope-from kientzle@freebsd.org) Received: from kientzle.com (h-66-166-149-50.snvacaid.covad.net [66.166.149.50]) by mx1.freebsd.org (Postfix) with ESMTP id 3F9A28FC23 for ; Thu, 6 Mar 2008 01:12:58 +0000 (UTC) (envelope-from kientzle@freebsd.org) Received: from [10.0.0.204] (p54.kientzle.com [66.166.149.54]) by kientzle.com (8.12.9/8.12.9) with ESMTP id m261CWMa090026; Wed, 5 Mar 2008 17:12:32 -0800 (PST) (envelope-from kientzle@freebsd.org) Message-ID: <47CF4500.2050509@freebsd.org> Date: Wed, 05 Mar 2008 17:12:32 -0800 From: Tim Kientzle User-Agent: Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7.12) Gecko/20060422 X-Accept-Language: en-us, en MIME-Version: 1.0 To: Bruce Evans References: <200802280409.m1S498YJ062561@repoman.freebsd.org> <20080228231522.F57564@delplex.bde.org> <20080229141527.N59899@delplex.bde.org> <18375.43955.908262.696223@hergotha.csail.mit.edu> <47C8D0AB.20506@freebsd.org> <20080302062610.V66431@delplex.bde.org> <47CA2192.8020802@FreeBSD.org> <20080303065527.K69705@delplex.bde.org> In-Reply-To: <20080303065527.K69705@delplex.bde.org> Content-Type: text/plain; charset=us-ascii; format=flowed Content-Transfer-Encoding: 7bit Cc: Jason Evans , Garrett Wollman , current@freebsd.org Subject: Breaking the crt1.o -> atexit() -> malloc() dependency X-BeenThere: freebsd-current@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: Discussions about the use of FreeBSD-current List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 06 Mar 2008 01:12:58 -0000 There was some recent discussion on the commit mailing list about how to disentangle crt1.o from malloc(). Here's a design that I think addresses all of the issues people raised, including the POSIX requirement that atexit() always be able to support 32 registrations. It does it without using sbrk() or mmap(), either. The basic idea is to lift the malloc() call up into atexit() and have atexit_register() use statically-allocated storage if atexit() didn't provide dynamically-allocated storage. This basically changes atexit() to something like this pseudocode: int atexit(void (*function)(void)) { struct atexit *storage = malloc(sizeof(struct atexit)); /* Note: If malloc() fails, __atexit_register will try * to statically allocate, so we don't check here * for malloc() failure. */ return __atexit_register(function, storage); } Then atexit_register either uses the block that was provided or grabs an item from a static pool if there wasn't one: /* 32 required by POSIX plus a few for crt1.o */ static struct atexit pool[40]; int atexit_register(void (*function)(void), struct atexit *storage) { if (storage == NULL) { storage = ... next item from static pool ... } storage.func = function; ... add storage block to linked list ... } Avoiding free() from the low-level code is a little trickier but I think it can be done by having the low-level code put (dynamically-allocated) blocks back onto a free list and having the higher-level atexit() release that list on the next registration. This should handle the case of a dynamic library being repeatedly loaded and unloaded. Of course, it's unnecessary to release the atexit storage on program exit. In particular, crt1.o can then call atexit_register(f, NULL) to register its exit functions without creating a dependency on malloc. This does require that atexit() and atexit_register() be in separate source files, but I think it addresses all of the other concerns people have raised. Cheers, Tim Kientzle