Waiting on more then one event -- Accept_r

Artyom <artyomtnk-/[email protected]>
Newsgroups gmane.comp.web.fastcgi.devel,gmane.spam.detected
Message-ID <[email protected]>
Hello,

There is a problem when I want to work with
multiple threads and receive other notifications
for example, timeout, cache notifications etc.

The purposed solution on the lists is:

pthread_mutex_lock
select(incoming fd,other event fd,timeout)
FCGX_Accept_r()
pthread_mutex_unlock

Comments: 
- I can't do select outside lock because
  I may find two threads accepting same request
  and one of them being blocked.
- FCGX_Accept_r does much more then just accept
  reads environment parameters from the socket
  etc... All this time other threads can not
  accept new connections.

For me ideal solution would be calling accept
outside the socket, unlocking mutex and continuing
to normal Accept_r. 

Something like that.
  pthread_mutex_lock
  select(incoming fd,other event fd,timeout)
  new_sock=accept(fd);
  pthread_mutex_unlock
  FCGX_Accept_r(new_sock)

Viewing the fcgiapp.c code I found that Accept_r
checks whether icpFd assigned the value, thus
I tried following way:
  request->ipcFd=
    accept(main_fd, (struct sockaddr *)&sa,&len);
  request->keepConnection=1;
and then
  FCGX_Accept_r(request)

It seems to be work and I had written a simple
program based on thread.c based on this techique
that accepts external signal (SIGINT) and performs
nice shutdown.

But I'm absolutely not sure if:
- is this correct way to do things?
- may this change in future?
- can similar API be added to the library? 
  if such way is OK I may write a patch and send.


Thanks,
  Artyom

P.S.: The program is attached.

___________________________________
fastcgi-developers mailing list
http://fastcgi.com/fastcgi-developers/
threaded.c (application/octet-stream, 3.4 KB)
/*
 * threaded.c -- A simple multi-threaded FastCGI application.
 */

#ifndef lint
static const char rcsid[] = "$Id: threaded.c,v 1.9 2001/11/20 03:23:21 robs Exp $";
#endif /* not lint */

#include "fcgi_config.h"

#include <pthread.h>
#include <sys/types.h>

#include <sys/un.h>
#include <netinet/tcp.h>

#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif

#include "fcgiapp.h"

#include <poll.h>
#include <fcntl.h>
#include <stdio.h>
#include <sys/socket.h>
#include <sys/select.h>
/* According to earlier standards */

#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#include <signal.h>

#define THREAD_COUNT 20

/* File descriptior shared between threads */
static int main_fd;

/* Exit Flag */
static int exitf=0;

/* Socket pair that is used for exit 
 * notification */
int pair[2];
void MyAccept(FCGX_Request *request)
{
	/* IS THIS CORRECT ???*/
	struct sockaddr sa;
	int len = sizeof(sa);
	request->ipcFd=accept(main_fd, (struct sockaddr *)&sa,&len);
	request->keepConnection=1;
	/* IS THIS CORRECT ???*/
}

static void *doit(void *a)
{
    int rc, thread_id = (int)a;
    pid_t pid = getpid();
    FCGX_Request request;
    char *server_name;

    FCGX_InitRequest(&request, main_fd, 0);

    for (;;)
    {
        static pthread_mutex_t accept_mutex = PTHREAD_MUTEX_INITIALIZER;

	/* LOCK RESOURCE:
	 * I WILL ACCEPT THE CONNECTION */

        pthread_mutex_lock(&accept_mutex);

	struct pollfd fdd[2];
	
	do{	
		if(exitf) {
        		pthread_mutex_unlock(&accept_mutex);
			goto end;
		}

		fdd[0].fd=main_fd; fdd[0].events=POLLIN ; fdd[0].revents=0;
		fdd[1].fd=pair[0]; fdd[1].events=POLLIN ; fdd[1].revents=0;

		/* Wait for two events:
		 * 1. New connection and then do accept
		 * 2. Exit message - exit and do clean up */

		poll(fdd,2,-1);

		if(fdd[1].revents) {
			exitf=1;
		}

		if(exitf) {
        		pthread_mutex_unlock(&accept_mutex);
			goto end;
		}

	} while(fdd[0].revents==0);
	
	MyAccept(&request);
	
	/* FREE RESOURCE: LET OTHERS ACCEPT CONNECTION */
        pthread_mutex_unlock(&accept_mutex);

	rc = FCGX_Accept_r(&request);
	if (rc < 0){
		break;
	}

        server_name = FCGX_GetParam("SERVER_NAME", request.envp);

        FCGX_FPrintF(request.out,
            "Content-type: text/html\r\n"
            "\r\n"
            "<title>FastCGI Hello! (multi-threaded C, fcgiapp library)</title>"
            "<h1>FastCGI Hello! (multi-threaded C, fcgiapp library)</h1>"
            "Thread %d, Process %ld<p>",
            thread_id, pid);

        sleep(1);

        FCGX_Finish_r(&request);
    }
end:
    printf("Exited %d\n",thread_id);
    return NULL;
}

void my_hand(int signum)
{
	printf("Got signal... Exiting\n");
	/* Set signal on the "EXIT" socket */
	write(pair[1],"0",1);
}


int main(void)
{
    int i;
    pthread_t id[THREAD_COUNT];

    FCGX_Init();

    main_fd=FCGX_OpenSocket("/tmp/a-sock",40);

    if(main_fd<0) {
	printf("Error\n");
	return 1;
    }

    /* Create pair of sockets for notification of exit
     * that allow to select two events */

    pipe(pair);
    signal(SIGINT,my_hand);

    for (i = 1; i < THREAD_COUNT; i++)
        pthread_create(&id[i], NULL, doit, (void*)i);

    doit(0);

    for(i = 1; i < THREAD_COUNT; i++)
	pthread_join(id[i],NULL);

    return 0;
}
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.