From nobody@FreeBSD.org  Mon Feb  6 17:08:43 2012
Return-Path: <nobody@FreeBSD.org>
Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34])
	by hub.freebsd.org (Postfix) with ESMTP id 1CF241065672
	for <freebsd-gnats-submit@FreeBSD.org>; Mon,  6 Feb 2012 17:08:43 +0000 (UTC)
	(envelope-from nobody@FreeBSD.org)
Received: from red.freebsd.org (red.freebsd.org [IPv6:2001:4f8:fff6::22])
	by mx1.freebsd.org (Postfix) with ESMTP id ED36F8FC08
	for <freebsd-gnats-submit@FreeBSD.org>; Mon,  6 Feb 2012 17:08:42 +0000 (UTC)
Received: from red.freebsd.org (localhost [127.0.0.1])
	by red.freebsd.org (8.14.4/8.14.4) with ESMTP id q16H8gtr052061
	for <freebsd-gnats-submit@FreeBSD.org>; Mon, 6 Feb 2012 17:08:42 GMT
	(envelope-from nobody@red.freebsd.org)
Received: (from nobody@localhost)
	by red.freebsd.org (8.14.4/8.14.4/Submit) id q16H8g8r052060;
	Mon, 6 Feb 2012 17:08:42 GMT
	(envelope-from nobody)
Message-Id: <201202061708.q16H8g8r052060@red.freebsd.org>
Date: Mon, 6 Feb 2012 17:08:42 GMT
From: Florian Wilkemeyer <fw@f-ws.de>
To: freebsd-gnats-submit@FreeBSD.org
Subject: pthread_create/join memory leak
X-Send-Pr-Version: www-3.1
X-GNATS-Notify:

>Number:         164828
>Category:       amd64
>Synopsis:       pthread_create/join memory leak
>Confidential:   no
>Severity:       non-critical
>Priority:       medium
>Responsible:    freebsd-amd64
>State:          closed
>Quarter:        
>Keywords:       
>Date-Required:  
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Mon Feb 06 17:10:09 UTC 2012
>Closed-Date:    Tue Feb 14 04:23:44 UTC 2012
>Last-Modified:  Tue Feb 14 04:23:44 UTC 2012
>Originator:     Florian Wilkemeyer
>Release:        9.0-RELEASE
>Organization:
>Environment:
FreeBSD 9test 9.0-RELEASE FreeBSD 9.0-RELEASE #0: Tue Jan  3 07:46:30 UTC 2012     root@farrell.cse.buffalo.edu:/usr/obj/usr/src/sys/GENERIC  amd64

>Description:
I recently noticed that pthread_create/join  leaks memory
when you're going to create & destroy masses of threads.



Test code: (compiled with gcc -o test test.c -lphtread) 

#include <pthread.h>


void *thrProc(void *arg){
        pthread_exit(NULL);
}


int main(){
        pthread_t thr;
        
        while(1){
                thr = NULL;
                pthread_create(&thr, NULL, thrProc, NULL);
                pthread_join(thr, NULL);
        }

        return 0;
}



The same code runs on 8.2 without problems:

FreeBSD wilkemeyer-laptop 8.2-RELEASE-p2 FreeBSD 8.2-RELEASE-p2 #0: Thu Jul 21 20:11:49 CEST 2011     root@wilkemeyer-laptop:/usr/obj/usr/src/sys/WILKEMEYER_LAPTOP  amd64





>How-To-Repeat:

#include <pthread.h>


void *thrProc(void *arg){
        pthread_exit(NULL);
}


int main(){
        pthread_t thr;
        
        while(1){
                thr = NULL;
                pthread_create(&thr, NULL, thrProc, NULL);
                pthread_join(thr, NULL);
        }

        return 0;
}

// compile with
// gcc -o test test.c -lphtread
//
>Fix:


>Release-Note:
>Audit-Trail:

From: dfilter@FreeBSD.ORG (dfilter service)
To: bug-followup@FreeBSD.org
Cc:  
Subject: Re: amd64/164828: commit references a PR
Date: Tue,  7 Feb 2012 02:57:49 +0000 (UTC)

 Author: davidxu
 Date: Tue Feb  7 02:57:36 2012
 New Revision: 231106
 URL: http://svn.freebsd.org/changeset/base/231106
 
 Log:
   Plug a memory leak. When a cached thread is reused, don't clear sleep
   queue pointers, just reuse it.
   
   PR:		164828
   MFC after:	1 week
 
 Modified:
   head/lib/libthr/thread/thr_list.c
   head/lib/libthr/thread/thr_private.h
 
 Modified: head/lib/libthr/thread/thr_list.c
 ==============================================================================
 --- head/lib/libthr/thread/thr_list.c	Tue Feb  7 02:21:46 2012	(r231105)
 +++ head/lib/libthr/thread/thr_list.c	Tue Feb  7 02:57:36 2012	(r231106)
 @@ -149,11 +149,16 @@ _thr_alloc(struct pthread *curthread)
  		if (total_threads > MAX_THREADS)
  			return (NULL);
  		atomic_fetchadd_int(&total_threads, 1);
 -		thread = malloc(sizeof(struct pthread));
 +		thread = calloc(1, sizeof(struct pthread));
  		if (thread == NULL) {
  			atomic_fetchadd_int(&total_threads, -1);
  			return (NULL);
  		}
 +		thread->sleepqueue = _sleepq_alloc();
 +		thread->wake_addr = _thr_alloc_wake_addr();
 +	} else {
 +		bzero(&thread->_pthread_startzero, 
 +			__rangeof(struct pthread, _pthread_startzero, _pthread_endzero));
  	}
  	if (curthread != NULL) {
  		THR_LOCK_ACQUIRE(curthread, &tcb_lock);
 @@ -163,10 +168,7 @@ _thr_alloc(struct pthread *curthread)
  		tcb = _tcb_ctor(thread, 1 /* initial tls */);
  	}
  	if (tcb != NULL) {
 -		memset(thread, 0, sizeof(*thread));
  		thread->tcb = tcb;
 -		thread->sleepqueue = _sleepq_alloc();
 -		thread->wake_addr = _thr_alloc_wake_addr();
  	} else {
  		thr_destroy(curthread, thread);
  		atomic_fetchadd_int(&total_threads, -1);
 @@ -194,8 +196,6 @@ _thr_free(struct pthread *curthread, str
  	}
  	thread->tcb = NULL;
  	if ((curthread == NULL) || (free_thread_count >= MAX_CACHED_THREADS)) {
 -		_sleepq_free(thread->sleepqueue);
 -		_thr_release_wake_addr(thread->wake_addr);
  		thr_destroy(curthread, thread);
  		atomic_fetchadd_int(&total_threads, -1);
  	} else {
 @@ -213,6 +213,10 @@ _thr_free(struct pthread *curthread, str
  static void
  thr_destroy(struct pthread *curthread __unused, struct pthread *thread)
  {
 +	if (thread->sleepqueue != NULL)
 +		_sleepq_free(thread->sleepqueue);
 +	if (thread->wake_addr != NULL)
 +		_thr_release_wake_addr(thread->wake_addr);
  	free(thread);
  }
  
 
 Modified: head/lib/libthr/thread/thr_private.h
 ==============================================================================
 --- head/lib/libthr/thread/thr_private.h	Tue Feb  7 02:21:46 2012	(r231105)
 +++ head/lib/libthr/thread/thr_private.h	Tue Feb  7 02:57:36 2012	(r231106)
 @@ -343,6 +343,7 @@ struct pthread_key {
   * Thread structure.
   */
  struct pthread {
 +#define _pthread_startzero	tid
  	/* Kernel thread id. */
  	long			tid;
  #define	TID_TERMINATED		1
 @@ -506,12 +507,6 @@ struct pthread {
  	/* Event */
  	td_event_msg_t		event_buf;
  
 -	struct wake_addr	*wake_addr;
 -#define WAKE_ADDR(td)           ((td)->wake_addr)
 -
 -	/* Sleep queue */
 -	struct	sleepqueue	*sleepqueue;
 -
  	/* Wait channel */
  	void			*wchan;
  
 @@ -526,6 +521,14 @@ struct pthread {
  
  	/* Deferred threads from pthread_cond_signal. */
  	unsigned int 		*defer_waiters[MAX_DEFER_WAITERS];
 +#define _pthread_endzero	wake_addr
 +
 +	struct wake_addr	*wake_addr;
 +#define WAKE_ADDR(td)           ((td)->wake_addr)
 +
 +	/* Sleep queue */
 +	struct	sleepqueue	*sleepqueue;
 +
  };
  
  #define THR_SHOULD_GC(thrd) 						\
 _______________________________________________
 svn-src-all@freebsd.org mailing list
 http://lists.freebsd.org/mailman/listinfo/svn-src-all
 To unsubscribe, send any mail to "svn-src-all-unsubscribe@freebsd.org"
 
State-Changed-From-To: open->patched 
State-Changed-By: davidxu 
State-Changed-When: Tue Feb 7 03:18:23 UTC 2012 
State-Changed-Why:  
A patch is committed. 

http://www.freebsd.org/cgi/query-pr.cgi?pr=164828 
State-Changed-From-To: patched->closed 
State-Changed-By: davidxu 
State-Changed-When: Tue Feb 14 04:23:07 UTC 2012 
State-Changed-Why:  
Fixed! 

http://www.freebsd.org/cgi/query-pr.cgi?pr=164828 
>Unformatted:
