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:
parent
fc5fc7dfa6
commit
ceb2f8cfc9
147
src/webserver.c
147
src/webserver.c
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue