Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 30 Oct 2000 22:48:05 +0100 (CET)
From:      tegge@trondheim.fast.no
To:        FreeBSD-gnats-submit@freebsd.org
Subject:   ports/22429: linuxthreads port compiles liblgcc_r using wrong pthread.h
Message-ID:  <200010302148.e9ULm5b42061@crash.trondheim.fast.no>

next in thread | raw e-mail | index | archive | help

>Number:         22429
>Category:       ports
>Synopsis:       linuxthreads port compiles liblgcc_r using wrong pthread.h
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    freebsd-ports
>State:          open
>Quarter:        
>Keywords:       
>Date-Required:
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Mon Oct 30 13:50:01 PST 2000
>Closed-Date:
>Last-Modified:
>Originator:     Tor Egge
>Release:        FreeBSD 5.0-CURRENT i386
>Organization:
Fast Search & Transfer ASA
>Environment:

	FreeBSD 5.0

>Description:

When the linuxthread port compiles liblgcc_r, the normal Makefile for
libgcc is included and some variables are overridden.  Unfortunately the
include path is not adjusted to use the linuxthread version of
pthread.h.  This results in mutexes in liblgcc_r getting the wrong
definition, size and initialization, easily leading to deadlock during
program startup (before main is called).

When mapping anonymous memory for thread stacks, only the initial stack
size is given as size argument to mmap().  On FreBSD, the maximum stack
size should be given as argument, otherwise the threads will only have
16 KB stack each.

When terminating a threaded application in a controlled fashion
(e.g. calling exit() from the main trhread after reaping all other
threads with pthread_join), global destructors are not always called.
This is due to the child process (thread manager) exiting before the
main thread has received the restart signal, causing the cancel signal
(SIGCHLD equivalent) to be delivered instead.

>How-To-Repeat:

Compile linuxthread port and have variables initialized to nonzero
values right after object_mutex in frame.o (in liblgcc_r.a).  The
threaded application might hang during startup due in __pthread_lock()
due to lock->__status being nonzero.

Compile a threaded application using more than 16 KB stack on each
thread.

Write a memory profiling tool and see memory leaks after controlled
application termination caused by destructors for global objects
not having been called.

>Fix:

To compile liblgcc using the correct pthread.h file:
------------------------
Index: files/Makefile.libgcc_r
===================================================================
RCS file: /home/ncvs/ports/devel/linuxthreads/files/Makefile.libgcc_r,v
retrieving revision 1.2
diff -u -r1.2 Makefile.libgcc_r
--- files/Makefile.libgcc_r	2000/07/12 01:43:01	1.2
+++ files/Makefile.libgcc_r	2000/10/30 20:43:21
@@ -4,6 +4,7 @@
 LIBDIR= lib/
 
 CFLAGS+=-D_PTHREADS -I../
+CFLAGS+=-I../sysdeps/i386 -I../sysdeps/pthread -I../sysdeps/unix/sysv/linux
 
 .include "/usr/src/gnu/lib/libgcc/Makefile"
 
------------------------

To allow more than 16 KB stack space for each thread:
------------------------
--- manager.c.orig	Sun Sep  3 01:09:04 2000
+++ manager.c	Sat Sep  9 21:25:47 2000
@@ -300,8 +300,8 @@
       /* Allocate space for stack and thread descriptor at default address */
       new_thread = default_new_thread;
       new_thread_bottom = (char *) (new_thread + 1) - stacksize;
-      if (mmap((caddr_t)((char *)(new_thread + 1) - INITIAL_STACK_SIZE),
-               INITIAL_STACK_SIZE, PROT_READ | PROT_WRITE | PROT_EXEC,
+      if (mmap((caddr_t)((char *)(new_thread + 1) - stacksize),
+               stacksize, PROT_READ | PROT_WRITE | PROT_EXEC,
                MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED | MAP_GROWSDOWN,
                -1, 0) == MAP_FAILED)
         /* Bad luck, this segment is already mapped. */
@@ -475,8 +475,8 @@
       {
 	if (new_thread->p_guardsize != 0)
 	  munmap(new_thread->p_guardaddr, new_thread->p_guardsize);
-	munmap((caddr_t)((char *)(new_thread+1) - INITIAL_STACK_SIZE),
-	       INITIAL_STACK_SIZE);
+	munmap((caddr_t)((char *)(new_thread+1) - STACK_SIZE),
+	       STACK_SIZE);
       }
     __pthread_handles[sseg].h_descr = NULL;
     __pthread_handles[sseg].h_bottom = NULL;
------------------------


To call destructors when main thread is exiting:
------------------------
--- manager.c.orig	Thu Sep 28 02:30:32 2000
+++ manager.c	Thu Sep 28 02:30:33 2000
@@ -660,10 +660,14 @@
 
 /* Process-wide exit() */
 
+extern int __pthread_exit_requested_bymainthread;
+
 static void pthread_handle_exit(pthread_descr issuing_thread, int exitcode)
 {
   pthread_descr th;
   __pthread_exit_requested = 1;
+  if (issuing_thread == __pthread_main_thread)
+    __pthread_exit_requested_bymainthread = 1;
   __pthread_exit_code = exitcode;
   /* Send the CANCEL signal to all running threads, including the main
      thread, but excluding the thread from which the exit request originated
--- pthread.c.orig	Thu Sep 28 02:30:32 2000
+++ pthread.c	Thu Sep 28 02:30:33 2000
@@ -164,6 +164,7 @@
 /* For process-wide exit() */
 
 int __pthread_exit_requested = 0;
+int __pthread_exit_requested_bymainthread = 0;
 int __pthread_exit_code = 0;
 
 /* Pointers that select new or old suspend/resume functions
@@ -680,6 +681,9 @@
   if (__pthread_exit_requested) {
     /* Main thread should accumulate times for thread manager and its
        children, so that timings for main thread account for all threads. */
+    if (self == __pthread_main_thread &&
+	__pthread_exit_requested_bymainthread != 0)
+	    return;
     if (self == __pthread_main_thread)
       waitpid(__pthread_manager_thread.p_pid, NULL, __WCLONE);
     _exit(__pthread_exit_code);
------------------------

>Release-Note:
>Audit-Trail:
>Unformatted:


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




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