Track threads in the webserver to better terminate. Next need to move the config_status stuff out of configfile and into webserver.c

This commit is contained in:
Ron Pedde 2004-09-30 03:03:18 +00:00
parent fc5fc7dfa6
commit ceb2f8cfc9
1 changed files with 101 additions and 46 deletions

View File

@ -63,9 +63,16 @@ typedef struct tag_ws_handler {
struct tag_ws_handler *next; struct tag_ws_handler *next;
} WS_HANDLER; } WS_HANDLER;
typedef struct tag_ws_connlist {
WS_CONNINFO *pwsc;
char *status;
struct tag_ws_connlist *next;
} WS_CONNLIST;
typedef struct tag_ws_private { typedef struct tag_ws_private {
WSCONFIG wsconfig; WSCONFIG wsconfig;
WS_HANDLER handlers; WS_HANDLER handlers;
WS_CONNLIST connlist;
int server_fd; int server_fd;
int stop; int stop;
int running; int running;
@ -76,6 +83,7 @@ typedef struct tag_ws_private {
pthread_mutex_t exit_mutex; pthread_mutex_t exit_mutex;
} WS_PRIVATE; } WS_PRIVATE;
/* /*
* Forwards * Forwards
*/ */
@ -103,6 +111,8 @@ int ws_registerhandler(WSHANDLE ws, char *regex,
int ws_decodepassword(char *header, char **username, char **password); int ws_decodepassword(char *header, char **username, char **password);
int ws_testrequestheader(WS_CONNINFO *pwsc, char *header, char *value); int ws_testrequestheader(WS_CONNINFO *pwsc, char *header, char *value);
char *ws_getrequestheader(WS_CONNINFO *pwsc, char *header); char *ws_getrequestheader(WS_CONNINFO *pwsc, char *header);
void ws_add_dispatch_thread(WS_PRIVATE *pwsp, WS_CONNINFO *pwsc);
void ws_remove_dispatch_thread(WS_PRIVATE *pwsp, WS_CONNINFO *pwsc);
/* /*
* Globals * Globals
@ -173,6 +183,7 @@ WSHANDLE ws_start(WSCONFIG *config) {
return NULL; return NULL;
memcpy(&pwsp->wsconfig,config,sizeof(WS_PRIVATE)); memcpy(&pwsp->wsconfig,config,sizeof(WS_PRIVATE));
pwsp->connlist.next=NULL;
pwsp->running=0; pwsp->running=0;
pwsp->threadno=0; pwsp->threadno=0;
pwsp->stop=0; pwsp->stop=0;
@ -212,6 +223,71 @@ WSHANDLE ws_start(WSCONFIG *config) {
return (WSHANDLE)pwsp; return (WSHANDLE)pwsp;
} }
/*
* ws_remove_dispatch_thread
*
* remove a dispatch thread from the thread list
*/
void ws_remove_dispatch_thread(WS_PRIVATE *pwsp, WS_CONNINFO *pwsc) {
WS_CONNLIST *pHead, *pTail;
if(pthread_mutex_lock(&pwsp->exit_mutex))
DPRINTF(ERR_FATAL,"Cannot lock condition mutex\n");
pHead=pTail=pwsp->connlist.next;
while((pHead) && (pHead->pwsc != pwsc)) {
pTail=pHead;
pHead=pHead->next;
}
if(pHead) {
pwsp->dispatch_threads--;
DPRINTF(ERR_DEBUG,"With thread %d exiting, %d are still running\n",
pwsc->threadno,pwsp->dispatch_threads);
pTail->next = pHead->next;
if(pHead->status)
free(pHead->status);
free(pHead);
/* signal condition in case something is waiting */
pthread_cond_signal(&pwsp->exit_cond);
}
pthread_mutex_unlock(&pwsp->exit_mutex);
}
/*
* ws_add_dispatch_thread
*
* Add a thread to the dispatch thread list
*/
void ws_add_dispatch_thread(WS_PRIVATE *pwsp, WS_CONNINFO *pwsc) {
WS_CONNLIST *pNew;
pNew=(WS_CONNLIST*)malloc(sizeof(WS_CONNLIST));
pNew->next=NULL;
pNew->pwsc=pwsc;
pNew->status=strdup("Initializing");
if(!pNew)
DPRINTF(ERR_FATAL,"Malloc: %s\n",strerror(errno));
if(pthread_mutex_lock(&pwsp->exit_mutex))
DPRINTF(ERR_FATAL,"Cannot lock condition mutex\n");
/* list is locked... */
pwsp->dispatch_threads++;
pNew->next = pwsp->connlist.next;
pwsp->connlist.next = pNew;
pthread_mutex_unlock(&pwsp->exit_mutex);
}
/* /*
* ws_stop * ws_stop
* *
@ -220,6 +296,8 @@ WSHANDLE ws_start(WSCONFIG *config) {
extern int ws_stop(WSHANDLE ws) { extern int ws_stop(WSHANDLE ws) {
WS_PRIVATE *pwsp = (WS_PRIVATE*)ws; WS_PRIVATE *pwsp = (WS_PRIVATE*)ws;
WS_HANDLER *current; WS_HANDLER *current;
WS_CONNLIST *pcl;
void *result;
DPRINTF(ERR_DEBUG,"ws_stop: %d threads\n",pwsp->dispatch_threads); DPRINTF(ERR_DEBUG,"ws_stop: %d threads\n",pwsp->dispatch_threads);
@ -238,11 +316,27 @@ extern int ws_stop(WSHANDLE ws) {
shutdown(pwsp->server_fd,SHUT_RDWR); shutdown(pwsp->server_fd,SHUT_RDWR);
r_close(pwsp->server_fd); /* this should tick off the listener */ r_close(pwsp->server_fd); /* this should tick off the listener */
/* Wait for all the threads to die */ /* wait for the server thread to terminate. SHould be quick! */
pthread_join(pwsp->server_tid,&result);
/* Give the threads an extra push */
if(pthread_mutex_lock(&pwsp->exit_mutex)) if(pthread_mutex_lock(&pwsp->exit_mutex))
DPRINTF(ERR_FATAL,"Cannot lock condition mutex\n"); DPRINTF(ERR_FATAL,"Cannot lock condition mutex\n");
/* wait for condition */ pcl=pwsp->connlist.next;
/* Closing the client sockets out from under the dispatch threads
* should cause the dispatch threads to exit out with an error.
*/
while(pcl) {
if(pcl->pwsc->fd) {
shutdown(pcl->pwsc->fd,SHUT_RDWR);
r_close(pcl->pwsc->fd);
}
pcl=pcl->next;
}
/* wait for the threads to be done */
while(pwsp->dispatch_threads) { while(pwsp->dispatch_threads) {
DPRINTF(ERR_DEBUG,"ws_stop: I still see %d threads\n",pwsp->dispatch_threads); DPRINTF(ERR_DEBUG,"ws_stop: I still see %d threads\n",pwsp->dispatch_threads);
pthread_cond_wait(&pwsp->exit_cond, &pwsp->exit_mutex); pthread_cond_wait(&pwsp->exit_cond, &pwsp->exit_mutex);
@ -275,28 +369,12 @@ void *ws_mainthread(void *arg) {
pthread_t tid; pthread_t tid;
char hostname[MAX_HOSTNAME]; char hostname[MAX_HOSTNAME];
if(pthread_mutex_lock(&pwsp->exit_mutex))
DPRINTF(ERR_FATAL,"Cannot lock condition mutex\n");
pwsp->dispatch_threads++;
pthread_mutex_unlock(&pwsp->exit_mutex);
while(1) { while(1) {
pwsc=(WS_CONNINFO*)malloc(sizeof(WS_CONNINFO)); pwsc=(WS_CONNINFO*)malloc(sizeof(WS_CONNINFO));
if(!pwsc) { if(!pwsc) {
/* can't very well service any more threads! */ /* can't very well service any more threads! */
DPRINTF(ERR_FATAL,"Error: %s\n",strerror(errno)); DPRINTF(ERR_FATAL,"Error: %s\n",strerror(errno));
pwsp->running=0; pwsp->running=0;
/* decrement the number of dispatch threads */
if(pthread_mutex_lock(&pwsp->exit_mutex))
DPRINTF(ERR_FATAL,"Cannot lock condition mutex\n");
pwsp->dispatch_threads--;
pthread_cond_signal(&pwsp->exit_cond);
pthread_mutex_unlock(&pwsp->exit_mutex);
return NULL; return NULL;
} }
@ -304,17 +382,11 @@ void *ws_mainthread(void *arg) {
if((fd=u_accept(pwsp->server_fd,hostname,MAX_HOSTNAME)) == -1) { if((fd=u_accept(pwsp->server_fd,hostname,MAX_HOSTNAME)) == -1) {
DPRINTF(ERR_DEBUG,"Dispatcher: accept failed: %s\n",strerror(errno)); DPRINTF(ERR_DEBUG,"Dispatcher: accept failed: %s\n",strerror(errno));
shutdown(pwsp->server_fd,SHUT_RDWR);
r_close(pwsp->server_fd); r_close(pwsp->server_fd);
pwsp->running=0; pwsp->running=0;
free(pwsc); free(pwsc);
/* decrement dispatch threads */
if(pthread_mutex_lock(&pwsp->exit_mutex))
DPRINTF(ERR_FATAL,"Cannot lock condition mutex\n");
pwsp->dispatch_threads--;
pthread_cond_signal(&pwsp->exit_cond);
pthread_mutex_unlock(&pwsp->exit_mutex);
DPRINTF(ERR_DEBUG,"Dispatcher: Aborting\n"); DPRINTF(ERR_DEBUG,"Dispatcher: Aborting\n");
return NULL; return NULL;
} }
@ -334,18 +406,12 @@ void *ws_mainthread(void *arg) {
ws_unlock_unsafe(); ws_unlock_unsafe();
/* now, throw off a dispatch thread */ /* now, throw off a dispatch thread */
if(pthread_mutex_lock(&pwsp->exit_mutex))
DPRINTF(ERR_FATAL,"Cannot lock condition mutex\n");
pwsp->dispatch_threads++; /* since ws_close will decrement if fail */
if((err=pthread_create(&tid,NULL,ws_dispatcher,(void*)pwsc))) { if((err=pthread_create(&tid,NULL,ws_dispatcher,(void*)pwsc))) {
pwsc->error=err; pwsc->error=err;
DPRINTF(ERR_WARN,"Could not spawn thread: %s\n",strerror(err)); DPRINTF(ERR_WARN,"Could not spawn thread: %s\n",strerror(err));
pthread_mutex_unlock(&pwsp->exit_mutex);
ws_close(pwsc); ws_close(pwsc);
} else { } else {
pthread_mutex_unlock(&pwsp->exit_mutex); ws_add_dispatch_thread(pwsp,pwsc);
pthread_detach(tid); pthread_detach(tid);
} }
} }
@ -384,26 +450,15 @@ void ws_close(WS_CONNINFO *pwsc) {
if((pwsc->close)||(pwsc->error)) { if((pwsc->close)||(pwsc->error)) {
DPRINTF(ERR_DEBUG,"Thread %d: Closing fd\n",pwsc->threadno); DPRINTF(ERR_DEBUG,"Thread %d: Closing fd\n",pwsc->threadno);
shutdown(pwsc->fd,SHUT_RDWR);
r_close(pwsc->fd); r_close(pwsc->fd);
free(pwsc->hostname); free(pwsc->hostname);
/* this thread is done */ /* this thread is done */
if(pthread_mutex_lock(&pwsp->exit_mutex)) ws_remove_dispatch_thread(pwsp, pwsc);
DPRINTF(ERR_FATAL,"Error: cannot lock condition mutex\n");
if(!pwsp->dispatch_threads) {
DPRINTF(ERR_FATAL,"Error: Bad dispatch thread count!\n");
} else {
pwsp->dispatch_threads--;
DPRINTF(ERR_INFO,"Thread %d: without me, there are only %d threads left\n",
pwsc->threadno,pwsp->dispatch_threads);
if(pthread_cond_signal(&pwsp->exit_cond))
DPRINTF(ERR_FATAL,"Error: cannot signal condition\n");
}
pthread_mutex_unlock(&pwsp->exit_mutex);
free(pwsc); free(pwsc);
pthread_exit(NULL);
} }
} }