Subject: scheduler activations problem ?
To: None <current-users@netbsd.org>
From: Mihai CHELARU <kefren@netbastards.org>
List: current-users
Date: 10/20/2003 14:39:13
Hi,

I wrote a small program that is used mainly to link two irc servers (one 
is using IPv4, the other one IPv6). I attached the source code below. 
The problem is that after it gets one connection it starts spawning 
threads like mad (at least that the opinion of `ps`, the test program 
doesn't show that this is happening). After it reaches 4578 lwps it 
stops. All these lwps are WCHANed as being in 'netcon'. Is my program 
problem or is a SA problem ?

$ ps sx | grep test | grep -v grep | wc -l
    4578
$ ps sx | grep test | grep -v grep | head
1000 6034 4085   0 4578 4578  28  0   344   464 sawait   S-   pa 0:36.02 
./test
1000 6034 4085   0 4574 4578   2  0   344   464 select   S-   pa 0:36.02 
./test
1000 6034 4085   0 4576 4578   2  0   344   464 select   S-   pa 0:36.02 
./test
1000 6034 4085   0 4577 4578   2  0   344   464 netcon   SW-  pa 0:36.02 
./test
1000 6034 4085   0 4575 4578   2  0   344   464 netcon   SW-  pa 0:36.02 
./test
1000 6034 4085   0 4573 4578   2  0   344   464 select   S-   pa 0:36.02 
./test
1000 6034 4085   0 4572 4578   2  0   344   464 netcon   SW-  pa 0:36.02 
./test
1000 6034 4085   0 4571 4578   2  0   344   464 netcon   SW-  pa 0:36.02 
./test
1000 6034 4085   0 4570 4578   2  0   344   464 netcon   SW-  pa 0:36.02 
./test
1000 6034 4085   0 4569 4578   2  0   344   464 netcon   SW-  pa 0:36.02 
./test


And here is the source code of test.c

#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/time.h>
#include <netinet/in.h>
#include <unistd.h>
#include <stdlib.h>
#include <netdb.h>
#include <pthread.h>
#include <signal.h>

#define INET_ADDR "80.86.105.74"
#define INET_PORT 6667
#define INET_ADDR2 "2001:470:1f00:477::2"
#define INET_PORT2 "7000"
#define MAXSOCKS 100
#define MAXNICKLEN 100

#define DEBUG

void           *
sender(void *voidsoc)
{
        fd_set          fd, fd2;
        int             s, s1, r, *stmp;
        char            buf[1000];
        struct timeval  to = {1, 0};

        stmp = (int *) (voidsoc);
        s = stmp[0];
        s1 = stmp[1];

#ifdef DEBUG
        printf("Socket2: %d %d\n", s, s1);
#endif

        FD_ZERO(&fd);
        FD_SET(s, &fd);
        for(;;) {
                fd2 = fd;
                if (!select(s + 1, &fd2, NULL, NULL, &to)) {
#ifdef DEBUG
                        printf("Timeout2\n");
#endif
                        if (stmp[2])
                                break;
                        continue;
                }
                r = recv(s, buf, 1000, MSG_PEEK);
                if (r < 1)
                        break;
                recv(s, buf, r, MSG_WAITALL);
#ifdef DEBUG
                printf("Write2: %.*s\n", r, buf);
#endif
                write(s1, buf, r);
        }
#ifdef DEBUG
        printf("Exiting thread2\n");
#endif
        close(s);
        stmp[3] = 1;
#ifdef DEBUG
        printf("Thread2 gone\n");
#endif
        pthread_exit(NULL);
}


void           *
persocket(void *voidsoc)
{
        int             s, s1, r, psoc[4], *destroy_mutex_1, gaie;
        char            buf[1000];
        fd_set          fd;
        pthread_t       pt;
        struct addrinfo hints, *res, *res0;

        struct sockaddr_in6 sa;
        struct timeval  to = {1, 0};
        s = accept((*(int *) (voidsoc)), NULL, NULL);
        destroy_mutex_1 = &psoc[3];
        destroy_mutex_1[0] = 0;
        psoc[2] = 0;
        /*
        s1=socket (PF_INET6, SOCK_STREAM, 6);
        sa.sin6_port=htons(INET_PORT2);
        sa.sin6_family=AF_INET6;
        sa.sin6_len=sizeof(sa);
        if (!inet_aton (INET_ADDR2,&sa.sin6_addr)) perror ("inet_aton");
        if (connect (s1,(struct sockaddr*)(&sa), sizeof(sa)) == -1) 
{perror("connect");close(s);close(s1);return NULL;}
        */

        hints.ai_family = PF_INET6;
        hints.ai_socktype = SOCK_STREAM;
        hints.ai_flags = 0;
        hints.ai_protocol = IPPROTO_TCP;
        hints.ai_addrlen = 0;
        hints.ai_canonname = NULL;
        hints.ai_addr = NULL;
        hints.ai_next = NULL;
        gaie = getaddrinfo(INET_ADDR2, INET_PORT2, &hints, &res0);
        if (gaie) {
                printf("getaddrinfo: %s\n", gai_strerror(gaie));
                close(s);
                return NULL;
        }
        for (res = res0; res0; res = res->ai_next) {
                s1 = socket(res->ai_family, res->ai_socktype, 
res->ai_protocol);
                if (s1 < 0)
                        continue;
                if (connect(s1, res->ai_addr, res->ai_addrlen) < 0) {
                        close(s1);
                        s1 = -1;
                        continue;
                }
                break;
        }
        freeaddrinfo(res0);
        if (s1 < 0) {
                perror("socket");
                close(s);
                return NULL;
        }

        psoc[0] = s1;
        psoc[1] = s;
        pthread_create(&pt, NULL, sender, (void *) (psoc));
        pthread_detach(pt);
//      pth_yield(NULL);

#ifdef DEBUG
        printf("Socket1: %d %d\n", s, s1);
#endif

        for (;;) {
                FD_ZERO(&fd);
                FD_SET(s, &fd);
                to.tv_sec = 1;
                to.tv_usec = 0;
                if (!select(s + 1, &fd, NULL, NULL, &to)) {
#ifdef DEBUG
                        printf("Timeout1\n");
#endif
                        if (destroy_mutex_1[0])
                                break;
                        continue;
                }
                r = recv(s, buf, 1000, MSG_PEEK);
                if (r < 1)
                        break;
                recv(s, buf, r, MSG_WAITALL);
#ifdef DEBUG
                printf("Write1: %.*s\n", r, buf);
#endif
                write(s1, buf, r);
        }
#ifdef DEBUG
        printf("Exiting thread1\n");
#endif
        psoc[2] = 1;
        while (!psoc[3]) {
                usleep(2000);
//              pth_yield(NULL);
        }
        close(s);
#ifdef DEBUG
        printf("Thread1 gone\n");
#endif


        pthread_exit(NULL);
}

main()
{
        int             s;
        struct sockaddr_in socka;
        fd_set          fs;
        pthread_t       pt;

#ifndef DEBUG
        if (fork())
                return 0;
#endif

        signal(SIGPIPE, SIG_IGN);

        s = socket(PF_INET, SOCK_STREAM, 6);
        memset(&socka, 0, sizeof(socka));
        socka.sin_len = sizeof(struct sockaddr_in);
        socka.sin_port = htons(INET_PORT);
        socka.sin_family = AF_INET;
        inet_aton (INET_ADDR, &socka.sin_addr);
        if (bind(s, (struct sockaddr *) (&socka), sizeof(socka)) == -1) 
{
                perror("bind");
                close(s);
                return 1;
        }
        if (listen(s, 500) == -1) {
                perror("listen");
                close(s);
                return 2;
        }
        for(;;) {
        FD_ZERO(&fs);
        FD_SET(s, &fs);
                select(s + 1, &fs, NULL, NULL, NULL);
                if (pthread_create(&pt, NULL, persocket, (void *) (&s)))
                        perror("pthread_create");
                if (pthread_detach(pt))
                        perror("pthread_detach");
//              pth_yield(NULL);
        }
        close(s);

}


Thanks,
Mihai