delorie.com/archives/browse.cgi   search  
Mail Archives: cygwin/2005/01/28/12:10:31

Mailing-List: contact cygwin-help AT cygwin DOT com; run by ezmlm
List-Subscribe: <mailto:cygwin-subscribe AT cygwin DOT com>
List-Archive: <http://sourceware.org/ml/cygwin/>
List-Post: <mailto:cygwin AT cygwin DOT com>
List-Help: <mailto:cygwin-help AT cygwin DOT com>, <http://sourceware.org/ml/#faqs>
Sender: cygwin-owner AT cygwin DOT com
Mail-Followup-To: cygwin AT cygwin DOT com
Delivered-To: mailing list cygwin AT cygwin DOT com
Message-ID: <000c01c5055c$23818cb0$173ca8c0@AlohaSunset.com>
From: "Mark Pizzolato" <list-cygwin AT subscriptions DOT pizzolato DOT net>
To: <cygwin AT cygwin DOT com>
Subject: pthreads leaks handles and threads when threads use sockets
Date: Fri, 28 Jan 2005 09:09:31 -0800
MIME-Version: 1.0
X-OriginalArrivalTime: 28 Jan 2005 17:09:37.0066 (UTC) FILETIME=[2549F0A0:01C5055C]
X-IsSubscribed: yes

------=_NextPart_000_0009_01C50519.1424E250
Content-Type: text/plain;
	format=flowed;
	charset="iso-8859-1";
	reply-type=original
Content-Transfer-Encoding: 7bit

I've been using clamav's clamd under cygwin and noticed that over time the 
handle count as viewed with TaskManager seems to grow to arbitrary values. 
I used clamd's option IdleTimeout set to 600 seconds which dramatically 
reduced the growth rate of the Handle Count.  Of course clamd has many 
things going on that could contribute to handle leakags, so I tried to write 
a simple program to demonstrate the problem.

The attached program demonstrates the problem when sockets are used and that 
things look pretty clean when they are not.

There  seems to be both a thread leakage issue and a separate handle leakage 
issue.

  Invoking the program as:
      threadtest -sockets 0
 creates groups of 5 threads simultaneously.  Each thread merely prints 
something and sleeps, prints something else and exits.  This is repeated 10 
times displaying the process handle count between each iteration.  While 
running and watching with Task Manager, the process thread counts seems to 
start at 2 and reach 7 at times and then return to 2.  The handle count 
grows during the first iteration but stays flat thereafter.


  Invoking the program as:
      threadtest -sockets 3
 creates groups of 5 threads simultaneously.  Each thread merely prints 
something and sleeps, connects a socket to the main thread, passes a little 
data and closes the socket.  This socket business is repeated 3 times after 
which the thread prints something else and exits.  This is repeated 10 times 
displaying the process handle count between each iteration.  While running 
and watching with Task Manager, the process thread counts seems to start at 
2 and reach 14 during the each iteration and drops back to 9 between 
iterations.  The handle count grows significantly during the first iteration 
but seems to grow by 10 or 11 between each subsequent iteration. 
 The -sockets 3 argument controls the number of sockets each thread creates 
during its life.  The amount of thread and handle leakage seems to be 
independent of the number of sockets the thread uses during its lifetime (as 
long as the number of sockets used is 1 or greater).

The number of threads created simultaneously can be controlled by 
specifying -threads n as command arguments.  The number of threads leaked 
seems to be directly related to the number of thread using sockets 
concurrently.  running the program with -sockets 3 and -threads 10 causes 
the thread count to jump to 24 during each iteration and drop back to 14 
between iterations, while the handle count seems to increase by 10 or 11 
between each iteration identical to the case described in the previous 
paragraph.

I hope this test can help someone familar enough with cygwin internals to 
help get this problem under control.

- Mark Pizzolato 

------=_NextPart_000_0009_01C50519.1424E250
Content-Type: text/plain;
	format=flowed;
	name="threadtest.c";
	reply-type=original
Content-Transfer-Encoding: quoted-printable
Content-Disposition: attachment;
	filename="threadtest.c"

#include <windows.h>

typedef enum _PROCESSINFOCLASS {
    ProcessHandleCount =3D 20,
} PROCESSINFOCLASS;
typedef LONG NTSTATUS;

int
GetHandleCount()
{
	static NTSTATUS
	(*lpNtQueryInformationProcess)(
		HANDLE           ProcessHandle,
		PROCESSINFOCLASS ProcessInformationClass,
		PVOID            ProcessInformation,
		ULONG            ProcessInformationLength,
		PULONG           ReturnLength ) =3D NULL;
	static int bInit =3D 0;
	int HandleCount =3D 0;

	if (FALSE =3D=3D bInit) {
		lpNtQueryInformationProcess =3D (NTSTATUS ( *)(HANDLE, PROCESSINFOCLASS, =
PVOID, ULONG, PULONG))GetProcAddress(GetModuleHandle("ntdll.dll"), "NtQuery=
InformationProcess");
		bInit =3D 1;
	}
	if (NULL !=3D lpNtQueryInformationProcess) {
		lpNtQueryInformationProcess( GetCurrentProcess(), ProcessHandleCount, &Ha=
ndleCount, sizeof(HandleCount), NULL );
	}
	return HandleCount;
}



#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include <time.h>
#include <errno.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

pthread_mutex_t mutex;
pthread_cond_t cond;
pthread_attr_t attr;
struct sockaddr_in server;
int sockets=3D2;
int threadgroup=3D5;

void *thread_code(void *arg)
{
	int threadnum =3D (int) arg;
	int i;
	int s;
	char buf[64];
	pthread_mutex_lock(&mutex);
	printf("Thread %d running...\n", threadnum);
	pthread_mutex_unlock(&mutex);
	for (i=3D0; i<sockets; ++i) {
		sleep(2);
		if((s =3D socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) =3D=3D -1) {
			pthread_mutex_lock(&mutex);
			printf("Thread %d socket() error\n", threadnum);
			pthread_mutex_unlock(&mutex);
			goto error;
		}
		if (-1 =3D=3D connect(s, (struct sockaddr *)&server, sizeof(server))) {
			pthread_mutex_lock(&mutex);
			printf("Thread %d connect() error\n", threadnum);
			pthread_mutex_unlock(&mutex);
			goto error;
		}
		snprintf(buf, sizeof(buf)-1, "Data From Thread: %d, Socket:%d", threadnum=
, i);
		if (-1 =3D=3D send(s, buf, strlen(buf), 0)) {
			pthread_mutex_lock(&mutex);
			printf("Thread %d send() error\n", threadnum);
			pthread_mutex_unlock(&mutex);
			goto error;
		}
		if (close(s)) {
			pthread_mutex_lock(&mutex);
			printf("Thread %d: close() error: %s\n", threadnum, strerror(errno));
			pthread_mutex_unlock(&mutex);
			goto error;
		}
	}
	sleep(2);
	pthread_mutex_lock(&mutex);
	printf("Thread %d done.\n", threadnum);
	pthread_mutex_unlock(&mutex);
	return;
=09
error:	pthread_mutex_lock(&mutex);
	printf("Thread %d error %s.\n", threadnum, strerror(errno));
	pthread_mutex_unlock(&mutex);
}

main(int argc, char **argv)
{
	int i, j, s;
	pthread_t thr_id;
	int true =3D 1;
	int HandleCount;

	while (--argc>0) {
		++argv;
		if (!strcmp("-sockets", *argv)) {
			++argv; --argc;
			sockets =3D atoi(*argv);
			continue;
		}
		if (!strcmp("-threads", *argv)) {
			++argv; --argc;
			threadgroup =3D atoi(*argv);
			continue;
		}
		printf("Unknown argument: %s\n", *argv);\
		printf("Usage: threadtest -s n -t n\n");
		printf("where:\n");
		printf(" -sockets   specifies the number of sockets that each thread shou=
ld\n");
		printf("            use during its life.  Interesting values are 0, 1 and=
\n");
		printf("            anything greater than 1.  The default value is 2.\n");
		printf(" -threads   specifies the number of threads to be created simulta=
neously.\n");
		printf("            The default value of 5 is sufficient to demonstrate t=
hread\n");
		printf("            and Handle leakage.\n");
		exit(1);
	}
	printf("Starting... Creating %d threads at a time with each thread using %=
d sockets\n",=20
	       threadgroup, sockets);

	if((s =3D socket(AF_INET, SOCK_STREAM, 0)) =3D=3D -1) {
		fprintf(stderr, "socket() error: %s\n", strerror(errno));
	}

	if(setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (void *) &true, sizeof(true)) =
=3D=3D -1) {
		fprintf(stderr, "setsockopt(SO_REUSEADDR) error: %s\n", strerror(errno));
	}

	memset((char *) &server, 0, sizeof(server));
	inet_aton("127.0.0.1", &server.sin_addr);
	server.sin_family =3D AF_INET;
	server.sin_port =3D htons(12345);
	if(bind(s, (struct sockaddr *) &server, sizeof(server)) =3D=3D -1) {
		fprintf(stderr, "bind() error: %s\n", strerror(errno));
	}
	if(listen(s, 2*threadgroup) =3D=3D -1) {
		fprintf(stderr, "listen() error: %s\n", strerror(errno));
	}

	sleep(4);
	if (pthread_mutex_init(&mutex, NULL) !=3D 0) {
		fprintf(stderr, "Error in pthread_mutex_init\n");
	}
	if (pthread_cond_init(&cond, NULL) !=3D 0) {
		fprintf(stderr, "Error in pthread_cond_init\n");
	}
=09=09
	if (pthread_attr_init(&attr) !=3D 0) {
		fprintf(stderr, "Error in pthread_attr_init\n");
	}
=09
	if (pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED) !=3D 0) {
		fprintf(stderr, "Error in pthread_attr_setdetachedstate\n");
	}

	printf("Initial Handle Count: %d\n", GetHandleCount());

	for (j=3D0; j<10; j++) {
		for (i=3D0; i<threadgroup; i++) {
			if (pthread_create(&thr_id, &attr, thread_code, (void *)i) !=3D 0) {
				fprintf(stderr,"pthread_create failed\n");
			}
		}
		for (i=3D0; i<sockets*threadgroup; i++) {
			int c;
			char buf[64];
			if (-1 =3D=3D (c=3Daccept(s, NULL, NULL))) {
				if (errno =3D=3D EINTR) {
					--i;
					continue;
				}
				fprintf(stderr, "accept() error: %s\n", strerror(errno));
			}
			memset(buf, 0, sizeof(buf));
			if (-1 =3D=3D recv(c, buf, sizeof(buf)-1, 0)) {
				fprintf(stderr, "recv() error: %s\n", strerror(errno));
			}
			pthread_mutex_lock(&mutex);
			printf("Received '%s' from thread\n", buf);
			pthread_mutex_unlock(&mutex);
			if (close(c)) {
				pthread_mutex_lock(&mutex);
				printf("Main Thread: close() error: %s\n", strerror(errno));
				pthread_mutex_unlock(&mutex);
			}
		}
		sleep(10);
		pthread_mutex_lock(&mutex);
		printf("Thread group %d complete...Handle Count: %d\n", j, GetHandleCount=
());
		pthread_mutex_unlock(&mutex);
	}
	close(s);
	printf("All done...\n");
	sleep(30);
}


------=_NextPart_000_0009_01C50519.1424E250
Content-Type: text/plain; charset=us-ascii

--
Unsubscribe info:      http://cygwin.com/ml/#unsubscribe-simple
Problem reports:       http://cygwin.com/problems.html
Documentation:         http://cygwin.com/docs.html
FAQ:                   http://cygwin.com/faq/
------=_NextPart_000_0009_01C50519.1424E250--

- Raw text -


  webmaster     delorie software   privacy  
  Copyright © 2019   by DJ Delorie     Updated Jul 2019