Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 5 Mar 2000 18:01:37 -0800 (PST)
From:      John Polstra <jdp@polstra.com>
To:        dmmiller@cvzoom.net
Cc:        current@freebsd.org
Subject:   Re: More "ld-elf.so.1: assert failed" messages
Message-ID:  <200003060201.SAA85727@vashon.polstra.com>
In-Reply-To: <38BB1E9C.CF44EC93@cvzoom.net>
References:  <38BA5751.2396AE87@cvzoom.net> <200002290104.RAA60914@vashon.polstra.com> <38BB1E9C.CF44EC93@cvzoom.net>

next in thread | previous in thread | raw e-mail | index | archive | help
Below is a patch for "src/libexec/rtld-elf" which should fix the
assert failures in wine.  I'd appreciate hearing from anybody who
tests this with multithreaded packages such as wine, JDK, Mozilla,
and linuxthreads.

Just a reminder -- be extra careful when messing with the dynamic
linker.  It's easy to paint yourself into a corner if it's broken
badly.  Make a backup copy of your current working dynamic linker
(/usr/libexec/ld-elf.so.1) before installing the experimental version.
Then if things fall apart you can recover with something like this:

    cd /usr/libexec
    chflags 0 ld-elf.so.1*
    mv ld-elf.so.1.good ld-elf.so.1

Thanks in advance for any testing you folks can make time to do.

John

Index: Makefile
===================================================================
RCS file: /home/ncvs/src/libexec/rtld-elf/Makefile,v
retrieving revision 1.10
diff -u -r1.10 Makefile
--- Makefile	2000/01/29 03:16:54	1.10
+++ Makefile	2000/03/01 02:39:13
@@ -3,7 +3,7 @@
 #
 MAINTAINER=	jdp
 PROG=		ld-elf.so.1
-SRCS=		rtld_start.S rtld.c lockdflt.c map_object.c malloc.c \
+SRCS=		rtld_start.S rtld.c map_object.c malloc.c \
 		xmalloc.c debug.c reloc.c
 MAN1=		rtld.1
 CFLAGS+=	-Wall -DFREEBSD_ELF -I${.CURDIR}/${MACHINE_ARCH} -I${.CURDIR}
Index: lockdflt.c
===================================================================
RCS file: lockdflt.c
diff -N lockdflt.c
--- /tmp/cvscXuMc22613	Sun Mar  5 17:48:37 2000
+++ /dev/null	Sun Mar  5 02:02:18 2000
@@ -1,89 +0,0 @@
-/*-
- * Copyright 1999, 2000 John D. Polstra.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * $FreeBSD: src/libexec/rtld-elf/lockdflt.c,v 1.4 2000/01/25 01:32:56 jdp Exp $
- */
-
-/*
- * Default thread locking implementation for the dynamic linker.  It
- * is used until the client registers a different implementation with
- * dllockinit().  The default implementation does mutual exclusion by
- * blocking almost all signals.  This is based on the observation that
- * most userland thread packages use signals to support preemption.
- */
-
-#include <dlfcn.h>
-#include <signal.h>
-#include <stdlib.h>
-
-#include "debug.h"
-#include "rtld.h"
-
-typedef struct Struct_LockDflt {
-    sigset_t lock_mask;
-    sigset_t old_mask;
-    int depth;
-} LockDflt;
-
-void
-lockdflt_acquire(void *lock)
-{
-    LockDflt *l = (LockDflt *)lock;
-    sigprocmask(SIG_BLOCK, &l->lock_mask, &l->old_mask);
-    assert(l->depth == 0);
-    l->depth++;
-}
-
-void *
-lockdflt_create(void *context)
-{
-    LockDflt *l;
-
-    l = NEW(LockDflt);
-    l->depth = 0;
-    sigfillset(&l->lock_mask);
-    sigdelset(&l->lock_mask, SIGTRAP);
-    sigdelset(&l->lock_mask, SIGABRT);
-    sigdelset(&l->lock_mask, SIGBUS);
-    sigdelset(&l->lock_mask, SIGSEGV);
-    sigdelset(&l->lock_mask, SIGKILL);
-    sigdelset(&l->lock_mask, SIGSTOP);
-    return l;
-}
-
-void
-lockdflt_destroy(void *lock)
-{
-    LockDflt *l = (LockDflt *)lock;
-    free(l);
-}
-
-void
-lockdflt_release(void *lock)
-{
-    LockDflt *l = (LockDflt *)lock;
-    assert(l->depth == 1);
-    l->depth--;
-    sigprocmask(SIG_SETMASK, &l->old_mask, NULL);
-}
Index: rtld.c
===================================================================
RCS file: /home/ncvs/src/libexec/rtld-elf/rtld.c,v
retrieving revision 1.43
diff -u -r1.43 rtld.c
--- rtld.c	2000/01/29 01:26:59	1.43
+++ rtld.c	2000/03/06 01:44:11
@@ -61,6 +61,9 @@
 typedef struct Struct_LockInfo {
     void *context;		/* Client context for creating locks */
     void *thelock;		/* The one big lock */
+    /* Debugging aids. */
+    volatile int rcount;	/* Number of readers holding lock */
+    volatile int wcount;	/* Number of writers holding lock */
     /* Methods */
     void (*rlock_acquire)(void *lock);
     void (*wlock_acquire)(void *lock);
@@ -70,6 +73,16 @@
 } LockInfo;
 
 /*
+ * This structure provides a reentrant way to keep a list of objects and
+ * check which ones have already been processed in some way.
+ */
+typedef struct Struct_DoneList {
+    Obj_Entry **objs;			/* Array of object pointers */
+    unsigned int num_alloc;		/* Allocated size of the array */
+    unsigned int num_used;		/* Number of array slots used */
+} DoneList;
+
+/*
  * Function declarations.
  */
 static const char *basename(const char *);
@@ -77,6 +90,7 @@
 static void digest_dynamic(Obj_Entry *);
 static Obj_Entry *digest_phdr(const Elf_Phdr *, int, caddr_t, const char *);
 static Obj_Entry *dlcheck(void *);
+static bool donelist_check(DoneList *, Obj_Entry *);
 static char *find_library(const char *, const Obj_Entry *);
 static void funclist_call(Funclist *);
 static void funclist_clear(Funclist *);
@@ -85,7 +99,7 @@
 static void funclist_push_tail(Funclist *, InitFunc);
 static const char *gethints(void);
 static void init_dag(Obj_Entry *);
-static void init_dag1(Obj_Entry *root, Obj_Entry *obj);
+static void init_dag1(Obj_Entry *root, Obj_Entry *obj, DoneList *);
 static void init_rtld(caddr_t);
 static bool is_exported(const Elf_Sym *);
 static void linkmap_add(Obj_Entry *);
@@ -93,6 +107,7 @@
 static int load_needed_objects(Obj_Entry *);
 static int load_preload_objects(void);
 static Obj_Entry *load_object(char *);
+static void lock_check(void);
 static void lock_nop(void *);
 static Obj_Entry *obj_from_addr(const void *);
 static void objlist_add(Objlist *, Obj_Entry *);
@@ -104,7 +119,7 @@
 static char *search_library_path(const char *, const char *);
 static void set_program_var(const char *, const void *);
 static const Elf_Sym *symlook_list(const char *, unsigned long,
-  Objlist *, const Obj_Entry **, bool in_plt);
+  Objlist *, const Obj_Entry **, bool in_plt, DoneList *);
 static void trace_loaded_objects(Obj_Entry *obj);
 static void unload_object(Obj_Entry *);
 static void unref_dag(Obj_Entry *);
@@ -128,7 +143,7 @@
 static Obj_Entry **obj_tail;	/* Link field of last object in list */
 static Obj_Entry *obj_main;	/* The main program shared object */
 static Obj_Entry obj_rtld;	/* The dynamic linker shared object */
-static unsigned long curmark;	/* Current mark value */
+static unsigned int obj_count;	/* Number of objects in obj_list */
 
 static Objlist list_global =	/* Objects dlopened with RTLD_GLOBAL */
   STAILQ_HEAD_INITIALIZER(list_global);
@@ -167,21 +182,44 @@
 char *__progname;
 char **environ;
 
+/*
+ * Fill in a DoneList with an allocation large enough to hold all of
+ * the currently-loaded objects.  Keep this as a macro since it calls
+ * alloca and we want that to occur within the scope of the caller.
+ */
+#define donelist_init(dlp)					\
+    ((dlp)->objs = alloca(obj_count * sizeof (dlp)->objs[0]),	\
+    assert((dlp)->objs != NULL),				\
+    (dlp)->num_alloc = obj_count,				\
+    (dlp)->num_used = 0)
+
 static __inline void
 rlock_acquire(void)
 {
     lockinfo.rlock_acquire(lockinfo.thelock);
+    atomic_incr_int(&lockinfo.rcount);
+    lock_check();
 }
 
 static __inline void
 wlock_acquire(void)
 {
     lockinfo.wlock_acquire(lockinfo.thelock);
+    atomic_incr_int(&lockinfo.wcount);
+    lock_check();
+}
+
+static __inline void
+rlock_release(void)
+{
+    atomic_decr_int(&lockinfo.rcount);
+    lockinfo.lock_release(lockinfo.thelock);
 }
 
 static __inline void
-lock_release(void)
+wlock_release(void)
 {
+    atomic_decr_int(&lockinfo.wcount);
     lockinfo.lock_release(lockinfo.thelock);
 }
 
@@ -316,6 +354,7 @@
     /* Link the main program into the list of objects. */
     *obj_tail = obj_main;
     obj_tail = &obj_main->next;
+    obj_count++;
     obj_main->refcount++;
 
     /* Initialize a fake symbol for resolving undefined weak references. */
@@ -366,7 +405,7 @@
     funclist_call(&initlist);
     wlock_acquire();
     funclist_clear(&initlist);
-    lock_release();
+    wlock_release();
 
     dbg("transferring control to program entry point = %p", obj_main->entry);
 
@@ -385,7 +424,7 @@
     Elf_Addr *where;
     Elf_Addr target;
 
-    wlock_acquire();
+    rlock_acquire();
     if (obj->pltrel)
 	rel = (const Elf_Rel *) ((caddr_t) obj->pltrel + reloff);
     else
@@ -403,7 +442,7 @@
       (void *)target, basename(defobj->path));
 
     reloc_jmpslot(where, target);
-    lock_release();
+    rlock_release();
     return target;
 }
 
@@ -671,6 +710,28 @@
 }
 
 /*
+ * If the given object is already in the donelist, return true.  Otherwise
+ * add the object to the list and return false.
+ */
+static bool
+donelist_check(DoneList *dlp, Obj_Entry *obj)
+{
+    unsigned int i;
+
+    for (i = 0;  i < dlp->num_used;  i++)
+	if (dlp->objs[i] == obj)
+	    return true;
+    /*
+     * Our donelist allocation should always be sufficient.  But if a
+     * threads package hasn't set up its locking properly, more shared
+     * objects could have been loaded since we allocated the list.
+     */
+    if (dlp->num_used < dlp->num_alloc)
+	dlp->objs[dlp->num_used++] = obj;
+    return false;
+}
+
+/*
  * Hash function for symbol table lookup.  Don't even think about changing
  * this.  It is specified by the System V ABI.
  */
@@ -741,6 +802,7 @@
 find_symdef(unsigned long symnum, Obj_Entry *refobj,
     const Obj_Entry **defobj_out, bool in_plt)
 {
+    DoneList donelist;
     const Elf_Sym *ref;
     const Elf_Sym *def;
     const Elf_Sym *symp;
@@ -755,11 +817,11 @@
     hash = elf_hash(name);
     def = NULL;
     defobj = NULL;
-    curmark++;
+    donelist_init(&donelist);
 
-    if (refobj->symbolic) {	/* Look first in the referencing object */
+    /* Look first in the referencing object if linked symbolically. */
+    if (refobj->symbolic && !donelist_check(&donelist, refobj)) {
 	symp = symlook_obj(name, hash, refobj, in_plt);
-	refobj->mark = curmark;
 	if (symp != NULL) {
 	    def = symp;
 	    defobj = refobj;
@@ -768,7 +830,7 @@
 
     /* Search all objects loaded at program start up. */
     if (def == NULL || ELF_ST_BIND(def->st_info) == STB_WEAK) {
-	symp = symlook_list(name, hash, &list_main, &obj, in_plt);
+	symp = symlook_list(name, hash, &list_main, &obj, in_plt, &donelist);
 	if (symp != NULL &&
 	  (def == NULL || ELF_ST_BIND(symp->st_info) != STB_WEAK)) {
 	    def = symp;
@@ -780,7 +842,8 @@
     STAILQ_FOREACH(elm, &refobj->dldags, link) {
 	if (def != NULL && ELF_ST_BIND(def->st_info) != STB_WEAK)
 	    break;
-	symp = symlook_list(name, hash, &elm->obj->dagmembers, &obj, in_plt);
+	symp = symlook_list(name, hash, &elm->obj->dagmembers, &obj, in_plt,
+	  &donelist);
 	if (symp != NULL &&
 	  (def == NULL || ELF_ST_BIND(symp->st_info) != STB_WEAK)) {
 	    def = symp;
@@ -790,7 +853,7 @@
 
     /* Search all RTLD_GLOBAL objects. */
     if (def == NULL || ELF_ST_BIND(def->st_info) == STB_WEAK) {
-	symp = symlook_list(name, hash, &list_global, &obj, in_plt);
+	symp = symlook_list(name, hash, &list_global, &obj, in_plt, &donelist);
 	if (symp != NULL &&
 	  (def == NULL || ELF_ST_BIND(symp->st_info) != STB_WEAK)) {
 	    def = symp;
@@ -919,23 +982,24 @@
 static void
 init_dag(Obj_Entry *root)
 {
-    curmark++;
-    init_dag1(root, root);
+    DoneList donelist;
+
+    donelist_init(&donelist);
+    init_dag1(root, root, &donelist);
 }
 
 static void
-init_dag1(Obj_Entry *root, Obj_Entry *obj)
+init_dag1(Obj_Entry *root, Obj_Entry *obj, DoneList *dlp)
 {
     const Needed_Entry *needed;
 
-    if (obj->mark == curmark)
+    if (donelist_check(dlp, obj))
 	return;
-    obj->mark = curmark;
     objlist_add(&obj->dldags, root);
     objlist_add(&root->dagmembers, obj);
     for (needed = obj->needed;  needed != NULL;  needed = needed->next)
 	if (needed->obj != NULL)
-	    init_dag1(root, needed->obj);
+	    init_dag1(root, needed->obj, dlp);
 }
 
 /*
@@ -971,6 +1035,7 @@
 	 */
 	obj_list = &obj_rtld;
 	obj_tail = &obj_rtld.next;
+	obj_count = 1;
 
 	relocate_objects(&obj_rtld, true);
     }
@@ -978,6 +1043,7 @@
     /* Make the object list empty again. */
     obj_list = NULL;
     obj_tail = &obj_list;
+    obj_count = 0;
 
     /* Replace the path with a dynamically allocated copy. */
     obj_rtld.path = xstrdup(obj_rtld.path);
@@ -1118,6 +1184,7 @@
 
 	*obj_tail = obj;
 	obj_tail = &obj->next;
+	obj_count++;
 	linkmap_add(obj);	/* for GDB */
 
 	dbg("  %p .. %p: %s", obj->mapbase,
@@ -1131,6 +1198,26 @@
     return obj;
 }
 
+/*
+ * Check for locking violations and die if one is found.
+ */
+static void
+lock_check(void)
+{
+    int rcount, wcount;
+
+    rcount = lockinfo.rcount;
+    wcount = lockinfo.wcount;
+    assert(rcount >= 0);
+    assert(wcount >= 0);
+    if (wcount > 1 || (wcount != 0 && rcount != 0)) {
+	_rtld_error("Application locking error: %d readers and %d writers"
+	  " in dynamic linker.  See DLLOCKINIT(3) in manual pages.",
+	  rcount, wcount);
+	die();
+    }
+}
+
 static void
 lock_nop(void *lock)
 {
@@ -1317,7 +1404,7 @@
     wlock_acquire();
     root = dlcheck(handle);
     if (root == NULL) {
-	lock_release();
+	wlock_release();
 	return -1;
     }
 
@@ -1336,7 +1423,7 @@
 	    if (obj->refcount == 0 && obj->fini != NULL)
 		funclist_push_tail(&finilist, obj->fini);
 
-	lock_release();
+	wlock_release();
 	funclist_call(&finilist);
 	wlock_acquire();
 	funclist_clear(&finilist);
@@ -1346,7 +1433,7 @@
 	unload_object(root);
 	GDB_STATE(RT_CONSISTENT);
     }
-    lock_release();
+    wlock_release();
     return 0;
 }
 
@@ -1373,10 +1460,8 @@
     if (lock_create == NULL) {
 	is_dflt = true;
 	context = NULL;
-	lock_create = lockdflt_create;
-	rlock_acquire = wlock_acquire = lockdflt_acquire;
-	lock_release = lockdflt_release;
-	lock_destroy = lockdflt_destroy;
+	rlock_acquire = wlock_acquire = lock_release = lock_nop;
+	lock_destroy = NULL;
 	context_destroy = NULL;
     }
 
@@ -1394,17 +1479,15 @@
     /*
      * Make sure the shared objects containing the locking methods are
      * fully bound, to avoid infinite recursion when they are called
-     * from the lazy binding code.
+     * from the lazy binding code.  Then allocate the lock we will use.
      */
     if (!is_dflt) {
 	prebind((void *)rlock_acquire);
 	prebind((void *)wlock_acquire);
 	prebind((void *)lock_release);
+	lockinfo.thelock = lock_create(lockinfo.context);
     }
 
-    /* Allocate our lock. */
-    lockinfo.thelock = lock_create(lockinfo.context);
-
     /* Record the new method information. */
     lockinfo.context = context;
     lockinfo.rlock_acquire = rlock_acquire;
@@ -1482,11 +1565,11 @@
     GDB_STATE(RT_CONSISTENT);
 
     /* Call the init functions with no locks held. */
-    lock_release();
+    wlock_release();
     funclist_call(&initlist);
     wlock_acquire();
     funclist_clear(&initlist);
-    lock_release();
+    wlock_release();
     return obj;
 }
 
@@ -1502,14 +1585,14 @@
     def = NULL;
     defobj = NULL;
 
-    wlock_acquire();
+    rlock_acquire();
     if (handle == NULL || handle == RTLD_NEXT) {
 	void *retaddr;
 
 	retaddr = __builtin_return_address(0);	/* __GNUC__ only */
 	if ((obj = obj_from_addr(retaddr)) == NULL) {
 	    _rtld_error("Cannot determine caller's shared object");
-	    lock_release();
+	    rlock_release();
 	    return NULL;
 	}
 	if (handle == NULL) {	/* Just the caller's shared object. */
@@ -1525,14 +1608,17 @@
 	}
     } else {
 	if ((obj = dlcheck(handle)) == NULL) {
-	    lock_release();
+	    rlock_release();
 	    return NULL;
 	}
 
 	if (obj->mainprog) {
+	    DoneList donelist;
+
 	    /* Search main program and all libraries loaded by it. */
-	    curmark++;
-	    def = symlook_list(name, hash, &list_main, &defobj, true);
+	    donelist_init(&donelist);
+	    def = symlook_list(name, hash, &list_main, &defobj, true,
+	      &donelist);
 	} else {
 	    /*
 	     * XXX - This isn't correct.  The search should include the whole
@@ -1544,12 +1630,12 @@
     }
 
     if (def != NULL) {
-	lock_release();
+	rlock_release();
 	return defobj->relocbase + def->st_value;
     }
 
     _rtld_error("Undefined symbol \"%s\"", name);
-    lock_release();
+    rlock_release();
     return NULL;
 }
 
@@ -1561,11 +1647,11 @@
     void *symbol_addr;
     unsigned long symoffset;
     
-    wlock_acquire();
+    rlock_acquire();
     obj = obj_from_addr(addr);
     if (obj == NULL) {
         _rtld_error("No shared object contains address");
-	lock_release();
+	rlock_release();
         return 0;
     }
     info->dli_fname = obj->path;
@@ -1604,7 +1690,7 @@
         if (info->dli_saddr == addr)
             break;
     }
-    lock_release();
+    rlock_release();
     return 1;
 }
 
@@ -1695,7 +1781,7 @@
 
 static const Elf_Sym *
 symlook_list(const char *name, unsigned long hash, Objlist *objlist,
-  const Obj_Entry **defobj_out, bool in_plt)
+  const Obj_Entry **defobj_out, bool in_plt, DoneList *dlp)
 {
     const Elf_Sym *symp;
     const Elf_Sym *def;
@@ -1705,9 +1791,8 @@
     def = NULL;
     defobj = NULL;
     STAILQ_FOREACH(elm, objlist, link) {
-	if (elm->obj->mark == curmark)
+	if (donelist_check(dlp, elm->obj))
 	    continue;
-	elm->obj->mark = curmark;
 	if ((symp = symlook_obj(name, hash, elm->obj, in_plt)) != NULL) {
 	    if (def == NULL || ELF_ST_BIND(symp->st_info) != STB_WEAK) {
 		def = symp;
@@ -1877,6 +1962,7 @@
 	    munmap(obj->mapbase, obj->mapsize);
 	    linkmap_delete(obj);
 	    *linkp = obj->next;
+	    obj_count--;
 	    obj_free(obj);
 	} else
 	    linkp = &obj->next;
Index: rtld.h
===================================================================
RCS file: /home/ncvs/src/libexec/rtld-elf/rtld.h,v
retrieving revision 1.15
diff -u -r1.15 rtld.h
--- rtld.h	2000/01/29 01:26:59	1.15
+++ rtld.h	2000/03/01 02:39:27
@@ -149,7 +149,6 @@
     Objlist dagmembers;		/* DAG has these members (%) */
     dev_t dev;			/* Object's filesystem's device */
     ino_t ino;			/* Object's inode number */
-    unsigned long mark;		/* Set to "curmark" to avoid repeat visits */
 } Obj_Entry;
 
 #define RTLD_MAGIC	0xd550b87a
@@ -170,10 +169,6 @@
 const Elf_Sym *find_symdef(unsigned long, Obj_Entry *, const Obj_Entry **,
   bool);
 void init_pltgot(Obj_Entry *);
-void lockdflt_acquire(void *);
-void *lockdflt_create(void *);
-void lockdflt_destroy(void *);
-void lockdflt_release(void *);
 void obj_free(Obj_Entry *);
 Obj_Entry *obj_new(void);
 int reloc_non_plt(Obj_Entry *, Obj_Entry *);
Index: alpha/rtld_machdep.h
===================================================================
RCS file: /home/ncvs/src/libexec/rtld-elf/alpha/rtld_machdep.h,v
retrieving revision 1.3
diff -u -r1.3 rtld_machdep.h
--- alpha/rtld_machdep.h	1999/08/28 00:10:13	1.3
+++ alpha/rtld_machdep.h	2000/03/06 01:37:22
@@ -34,4 +34,8 @@
 
 void reloc_jmpslot(Elf_Addr *, Elf_Addr);
 
+/* Atomically increment / decrement an int. */
+void atomic_incr_int(volatile int *);
+void atomic_decr_int(volatile int *);
+
 #endif
Index: alpha/rtld_start.S
===================================================================
RCS file: /home/ncvs/src/libexec/rtld-elf/alpha/rtld_start.S,v
retrieving revision 1.3
diff -u -r1.3 rtld_start.S
--- alpha/rtld_start.S	1999/08/28 00:10:13	1.3
+++ alpha/rtld_start.S	2000/03/06 01:37:58
@@ -166,6 +166,24 @@
 	jmp     $31, ($27)
 	.end _rtld_bind_start
  
+/* Atomically increment an int. */
+LEAF(atomic_incr_int, 1)
+0:	ldl_l	t0, 0(a0)
+	addq	t0, 1, t0
+	stl_c	t0, 0(a0)
+	beq	t0, 1f
+	mb
+	RET
+1:	br	0b
+	END(atomic_incr_int)
 
-
-
+/* Atomically decrement an int. */
+LEAF(atomic_decr_int, 1)
+0:	ldl_l	t0, 0(a0)
+	subq	t0, 1, t0
+	stl_c	t0, 0(a0)
+	beq	t0, 1f
+	mb
+	RET
+1:	br	0b
+	END(atomic_decr_int)
Index: i386/rtld_machdep.h
===================================================================
RCS file: /home/ncvs/src/libexec/rtld-elf/i386/rtld_machdep.h,v
retrieving revision 1.3
diff -u -r1.3 rtld_machdep.h
--- i386/rtld_machdep.h	1999/08/28 00:10:14	1.3
+++ i386/rtld_machdep.h	2000/03/06 01:40:47
@@ -41,4 +41,18 @@
 	(*(Elf_Addr *)(where) = (Elf_Addr)(target));	\
     } while (0)
 
+/* Atomically increment / decrement an int. */
+
+static __inline void
+atomic_incr_int(volatile int *p)
+{
+    __asm __volatile("lock; incl %0" : "=m" (*p) : "0" (*p));
+}
+
+static __inline void
+atomic_decr_int(volatile int *p)
+{
+    __asm __volatile("lock; decl %0" : "=m" (*p) : "0" (*p));
+}
+
 #endif


To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-current" in the body of the message




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200003060201.SAA85727>