Subject: pkg/17944: pth gets deadlocked and pth-syscall aborts with "SCHEDULER INTERNAL ERROR"
To: None <gnats-bugs@gnats.netbsd.org>
From: None <ChristianBiere@gmx.de>
List: netbsd-bugs
Date: 08/14/2002 18:10:29
>Number:         17944
>Category:       pkg
>Synopsis:       pth gets deadlocked and pth-syscall aborts with "SCHEDULER INTERNAL ERROR"
>Confidential:   no
>Severity:       non-critical
>Priority:       low
>Responsible:    pkg-manager
>State:          open
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Wed Aug 14 18:11:00 PDT 2002
>Closed-Date:
>Last-Modified:
>Originator:     Christian Biere
>Release:        1.6_BETA4
>Organization:
>Environment:
NetBSD localhost 1.6_BETA4 NetBSD 1.6_BETA4 (DURON) #1: Sat Aug 10 12:09:01 CEST 2002     root@localhost:/usr/src-1-6/sys/arch/i386/compile/DURON i386

>Description:
I'm experimenting with a program which should handle many connections
using one thread per connection. If I install pkgsrc/devel/pth I get the following result:

$ ./main
Idle!
fd=256
fd=257
fd=258
fd=259
fd=260
fd=261
**Pth** SCHEDULER INTERNAL ERROR: no more thread(s) available to schedule!?!?
Abort trap

If install pkgsrc/devel/pth-syscall instead the process will hang forever after "fd=256". I use the IP 1.2.3.4 because it takes a moment until the connect() fails and I really get 256 descriptors. As you can see I set FD_SETSIZE to 2048 and I should be able to open this many descriptors or socket() should fail. I've submitted this bug to the author but it might be NetBSD-specific.

Regards,
Christian
>How-To-Repeat:
main.c:
#define FD_SETSIZE 2048

#define ADDR_IP "1.2.3.4"
#define ADDR_PORT 8000

#include <pth.h>

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <unistd.h>
#include <fcntl.h>
#include <time.h>

int wait_select(int fd, time_t timeout) {
    struct timeval tv = {
                            timeout, 0
                        };
    fd_set fds;

    FD_ZERO(&fds);
    FD_SET(fd, &fds);
    return pth_select(fd+1, &fds, &fds, &fds, &tv);
}

static int connect_this(u_int32_t ip, u_int16_t port) {
    struct sockaddr_in s_addr;
    int fd = -1;

    if ((fd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
        perror("connect_this() failed");
        goto failure;
    }
    memset(&s_addr, 0, sizeof(s_addr));
    s_addr.sin_family = AF_INET;
    s_addr.sin_port = htons(port);
    memcpy(&s_addr.sin_addr, &ip, sizeof(struct in_addr));
    if ((pth_connect(fd, (struct sockaddr *)&s_addr, sizeof(s_addr))) == -1)
        if (errno != EINPROGRESS) {
            perror("pth_connect() failed");
            goto failure;
        }
    return fd;

failure:
    if (fd != -1)
        close(fd);
    return -1;
}

static void *my_thread(void *arg) {
    u_int32_t   ip;
    int ret, fd = -1;

    pth_sleep(2);
    if ((ret = inet_pton(AF_INET, ADDR_IP, &ip)) != 1) {
        perror( ret == -1
                ? "inet_pton() failed"
                : "inet_pton() failed: Could not parse address '" ADDR_IP "'"
              );
        goto cleanup;
    }
    if ((fd = connect_this(ip, ADDR_PORT)) == -1)
        goto cleanup;
    printf("fd=%d\n", fd);
    if ((ret = wait_select(fd, 5)) <= 0) {
        if (ret == -1)
            perror("is_writeable");
        goto cleanup;
    }

cleanup:
    if (fd != -1)
        close(fd);
    return NULL;
}
void *idle_thread(void *arg) {
    while(1) {
        printf("Idle!\n");
        pth_sleep(5);
    }
    return NULL;
}

int main(int argc, char *argv[]) {
    int thread_counter = 0;
    pth_attr_t attr;

    pth_init();
    attr = pth_attr_new();
    pth_attr_set(attr, PTH_ATTR_STACK_SIZE, 64*1024);
    pth_attr_set(attr, PTH_ATTR_JOINABLE, FALSE);
    pth_attr_set(attr, PTH_ATTR_NAME, "handler");

    while (thread_counter++ < 257)
        if (pth_spawn(attr, &my_thread, NULL) == NULL)
            perror("pth_spawn() failed");

    pth_join(pth_spawn(NULL, &idle_thread, NULL), NULL);
    return EXIT_SUCCESS;
}
---------------------------



Makefile:
CC = gcc
CFLAGS = -g -Wall `pth-config --cflags --all`
LDFLAGS = `pth-config --ldflags --all`
LIBS = `pth-config --libs`

all:
        $(CC) $(CPPFLAGS) $(CFLAGS) -o main main.c $(LDFLAGS) $(LIBS)

clean:  
        rm -rf main *.core



>Fix:

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