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;
}