fixed httpd to react to request immediate when threaded
This commit is contained in:
parent
681e50822c
commit
17d05bb1e0
@ -25,6 +25,7 @@
|
||||
|
||||
#include "httpd.h"
|
||||
#include "../cmn/mem.h"
|
||||
#include "../cmn/syscall.h"
|
||||
#include <qse/cmn/chr.h>
|
||||
#include <qse/cmn/str.h>
|
||||
#include <qse/cmn/mbwc.h>
|
||||
@ -627,67 +628,93 @@ httpd->cbs.on_error (httpd, l).... */
|
||||
static int make_fd_set_from_client_array (
|
||||
qse_httpd_t* httpd, fd_set* r, fd_set* w, int for_rdwr)
|
||||
{
|
||||
/* qse_http_loop() sets for_rdwr to true.
|
||||
* response_thread() sets for_rdwr to false.
|
||||
*
|
||||
* qse_http_loop()
|
||||
* - accepts a new client connection
|
||||
* - reads a client request
|
||||
* - writes back a response to a client request if not threaded.
|
||||
*
|
||||
* response_thread()
|
||||
* - writes back a response to a client request if threaded.
|
||||
*/
|
||||
|
||||
int fd, max = -1;
|
||||
client_array_t* ca = &httpd->client.array;
|
||||
|
||||
if (r && for_rdwr)
|
||||
if (for_rdwr)
|
||||
{
|
||||
/* qse_http_loop() needs to monitor listner handles
|
||||
* to handle a new client connection. */
|
||||
max = httpd->listener.max;
|
||||
*r = httpd->listener.set;
|
||||
}
|
||||
if (w)
|
||||
else
|
||||
{
|
||||
FD_ZERO (w);
|
||||
FD_ZERO (r);
|
||||
|
||||
#if defined(HAVE_PTHREAD)
|
||||
/* select() in response_thread() needs to be aborted
|
||||
* if it's blocking on a fd_set previously composed
|
||||
* when a new task is enqueued. it can select() on new
|
||||
* fd_set quickly.
|
||||
*/
|
||||
QSE_ASSERT (httpd->threaded);
|
||||
FD_SET (httpd->client.pfd[0], r);
|
||||
max = httpd->client.pfd[0];
|
||||
#endif
|
||||
}
|
||||
FD_ZERO (w);
|
||||
|
||||
for (fd = 0; fd < ca->capa; fd++)
|
||||
{
|
||||
if (ca->data[fd].htrd)
|
||||
{
|
||||
if (r && !ca->data[fd].bad)
|
||||
if (!ca->data[fd].bad)
|
||||
{
|
||||
if (for_rdwr)
|
||||
{
|
||||
/* add a client-side handle to the read set */
|
||||
/* add a client-side handle to the read set
|
||||
* only for qse_httpd_loop(). */
|
||||
FD_SET (ca->data[fd].handle.i, r);
|
||||
if (ca->data[fd].handle.i > max) max = ca->data[fd].handle.i;
|
||||
}
|
||||
|
||||
if (ca->data[fd].task.queue.head &&
|
||||
ca->data[fd].task.queue.head->task.trigger.i >= 0)
|
||||
if (!httpd->threaded || !for_rdwr)
|
||||
{
|
||||
/* if a trigger is available, add it to the read set also */
|
||||
FD_SET (ca->data[fd].task.queue.head->task.trigger.i, r);
|
||||
if (ca->data[fd].task.queue.head->task.trigger.i > max)
|
||||
max = ca->data[fd].task.queue.head->task.trigger.i;
|
||||
/* a trigger is a handle to monitor to check
|
||||
* if there is data avaiable to write back to the client.
|
||||
* if it is not threaded, qse_httpd_loop() needs to
|
||||
* monitor trigger handles. if it is threaded,
|
||||
* response_thread() needs to monitor these handles */
|
||||
|
||||
if (ca->data[fd].task.queue.head &&
|
||||
ca->data[fd].task.queue.head->task.trigger.i >= 0)
|
||||
{
|
||||
/* if a trigger is available, add it to the read set also. */
|
||||
FD_SET (ca->data[fd].task.queue.head->task.trigger.i, r);
|
||||
if (ca->data[fd].task.queue.head->task.trigger.i > max)
|
||||
max = ca->data[fd].task.queue.head->task.trigger.i;
|
||||
}
|
||||
}
|
||||
}
|
||||
#if 0
|
||||
if (w && (ca->data[fd].task.queue.count > 0 || ca->data[fd].bad))
|
||||
|
||||
if (ca->data[fd].bad ||
|
||||
(ca->data[fd].task.queue.head &&
|
||||
ca->data[fd].task.queue.head->task.trigger.i <= -1))
|
||||
{
|
||||
/* add it to the set if it has a response to send */
|
||||
/* add a client-side handle to the write set
|
||||
* if the client is already marked bad or
|
||||
* the current task enqueued didn't specify a trigger.
|
||||
*
|
||||
* if the task doesn't have a trigger, i perform
|
||||
* the task so long as the client side-handle is
|
||||
* available for writing in the main loop.
|
||||
*/
|
||||
FD_SET (ca->data[fd].handle.i, w);
|
||||
if (ca->data[fd].handle.i > max) max = ca->data[fd].handle.i;
|
||||
}
|
||||
#endif
|
||||
if (w)
|
||||
{
|
||||
if (ca->data[fd].bad ||
|
||||
(ca->data[fd].task.queue.head &&
|
||||
ca->data[fd].task.queue.head->task.trigger.i <= -1))
|
||||
{
|
||||
/* add a client-side handle to the write set
|
||||
* if the client is already marked bad or
|
||||
* the current task enqueued didn't specify a trigger.
|
||||
*
|
||||
* if the task doesn't have a trigger, i perform
|
||||
* the task so long as the client side-handle is
|
||||
* available for writing in the main loop.
|
||||
*/
|
||||
FD_SET (ca->data[fd].handle.i, w);
|
||||
if (ca->data[fd].handle.i > max) max = ca->data[fd].handle.i;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -727,9 +754,6 @@ static void* response_thread (void* arg)
|
||||
fd_set r, w;
|
||||
struct timeval tv;
|
||||
|
||||
tv.tv_sec = 1;
|
||||
tv.tv_usec = 0;
|
||||
|
||||
pthread_mutex_lock (&httpd->client.mutex);
|
||||
max = make_fd_set_from_client_array (httpd, &r, &w, 0);
|
||||
pthread_mutex_unlock (&httpd->client.mutex);
|
||||
@ -742,10 +766,11 @@ static void* response_thread (void* arg)
|
||||
pthread_mutex_lock (&httpd->client.mutex);
|
||||
|
||||
gettimeofday (&now, QSE_NULL);
|
||||
timeout.tv_sec = now.tv_sec + 2;
|
||||
timeout.tv_sec = now.tv_sec + 1;
|
||||
timeout.tv_nsec = now.tv_usec * 1000;
|
||||
|
||||
pthread_cond_timedwait (&httpd->client.cond, &httpd->client.mutex, &timeout);
|
||||
pthread_cond_timedwait (
|
||||
&httpd->client.cond, &httpd->client.mutex, &timeout);
|
||||
max = make_fd_set_from_client_array (httpd, &r, &w, 0);
|
||||
|
||||
pthread_mutex_unlock (&httpd->client.mutex);
|
||||
@ -753,6 +778,9 @@ static void* response_thread (void* arg)
|
||||
|
||||
if (httpd->stopreq) break;
|
||||
|
||||
tv.tv_sec = 1;
|
||||
tv.tv_usec = 0;
|
||||
|
||||
n = select (max + 1, &r, &w, QSE_NULL, &tv);
|
||||
if (n <= -1)
|
||||
{
|
||||
@ -766,29 +794,18 @@ qse_fprintf (QSE_STDERR, QSE_T("Error: select returned failure - %hs\n"), strerr
|
||||
continue;
|
||||
}
|
||||
|
||||
if (FD_ISSET (httpd->client.pfd[0], &r))
|
||||
{
|
||||
qse_mchar_t dummy;
|
||||
QSE_READ (httpd->client.pfd[0], &dummy, 1);
|
||||
}
|
||||
|
||||
for (fd = 0; fd < httpd->client.array.capa; fd++)
|
||||
{
|
||||
qse_httpd_client_t* client = &httpd->client.array.data[fd];
|
||||
|
||||
if (!client->htrd) continue;
|
||||
|
||||
/* ---------------------------------------------- */
|
||||
#if 0
|
||||
if (FD_ISSET(client->handle.i, &w))
|
||||
{
|
||||
if (client->bad)
|
||||
{
|
||||
}
|
||||
else if (client->task.queue.count > 0)
|
||||
{
|
||||
if (client->task.queue.head->task.trigger.i <= -1 ||
|
||||
FD_ISSET(client->task.queue.head->task.trigger.i, &r))
|
||||
{
|
||||
perform_task (httpd, client);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if (client->bad)
|
||||
{
|
||||
/*shutdown (client->handle.i, SHUT_RDWR);*/
|
||||
@ -796,7 +813,7 @@ qse_fprintf (QSE_STDERR, QSE_T("Error: select returned failure - %hs\n"), strerr
|
||||
delete_from_client_array (httpd, fd);
|
||||
pthread_mutex_unlock (&httpd->client.mutex);
|
||||
}
|
||||
else
|
||||
else if (client->task.queue.head)
|
||||
{
|
||||
if (client->task.queue.head->task.trigger.i <= -1 ||
|
||||
FD_ISSET(client->task.queue.head->task.trigger.i, &r))
|
||||
@ -805,12 +822,13 @@ qse_fprintf (QSE_STDERR, QSE_T("Error: select returned failure - %hs\n"), strerr
|
||||
tv.tv_usec = 0;
|
||||
FD_ZERO (&w);
|
||||
FD_SET (client->handle.i, &w);
|
||||
n = select (max + 1, QSE_NULL, &w, QSE_NULL, &tv);
|
||||
n = select (client->handle.i + 1, QSE_NULL, &w, QSE_NULL, &tv);
|
||||
if (n > 0 && FD_ISSET(client->handle.i, &w))
|
||||
{
|
||||
perform_task (httpd, client);
|
||||
}
|
||||
}
|
||||
}
|
||||
/* ---------------------------------------------- */
|
||||
}
|
||||
}
|
||||
|
||||
@ -903,17 +921,30 @@ int qse_httpd_loop (qse_httpd_t* httpd, int threaded)
|
||||
/* start the response sender as a thread */
|
||||
if (threaded)
|
||||
{
|
||||
pthread_mutex_init (&httpd->client.mutex, QSE_NULL);
|
||||
pthread_cond_init (&httpd->client.cond, QSE_NULL);
|
||||
|
||||
if (pthread_create (
|
||||
&response_thread_id, QSE_NULL,
|
||||
response_thread, httpd) != 0)
|
||||
if (QSE_PIPE(httpd->client.pfd) == 0)
|
||||
{
|
||||
pthread_cond_destroy (&httpd->client.cond);
|
||||
pthread_mutex_destroy (&httpd->client.mutex);
|
||||
int i;
|
||||
for (i = 0; i < 2; i++)
|
||||
{
|
||||
int flags = QSE_FCNTL (httpd->client.pfd[i], F_GETFD, 0);
|
||||
if (flags >= 0)
|
||||
QSE_FCNTL (httpd->client.pfd[i], F_SETFD, flags | FD_CLOEXEC);
|
||||
}
|
||||
|
||||
pthread_mutex_init (&httpd->client.mutex, QSE_NULL);
|
||||
pthread_cond_init (&httpd->client.cond, QSE_NULL);
|
||||
|
||||
if (pthread_create (
|
||||
&response_thread_id, QSE_NULL,
|
||||
response_thread, httpd) != 0)
|
||||
{
|
||||
pthread_cond_destroy (&httpd->client.cond);
|
||||
pthread_mutex_destroy (&httpd->client.mutex);
|
||||
QSE_CLOSE (httpd->client.pfd[1]);
|
||||
QSE_CLOSE (httpd->client.pfd[0]);
|
||||
}
|
||||
else httpd->threaded = 1;
|
||||
}
|
||||
else httpd->threaded = 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -935,7 +966,6 @@ int qse_httpd_loop (qse_httpd_t* httpd, int threaded)
|
||||
if (httpd->threaded) pthread_mutex_unlock (&httpd->client.mutex);
|
||||
#endif
|
||||
|
||||
/*n = select (max + 1, &r, &w, QSE_NULL, &tv);*/
|
||||
n = select (max + 1, &r, &w, QSE_NULL, &tv);
|
||||
if (n <= -1)
|
||||
{
|
||||
@ -984,31 +1014,6 @@ qse_fprintf (QSE_STDERR, QSE_T("Error: select returned failure\n"));
|
||||
}
|
||||
|
||||
|
||||
/*----------------------------------------------------------*/
|
||||
#if 0
|
||||
if (!httpd->threaded && FD_ISSET(client->handle.i, &w))
|
||||
{
|
||||
/* output is handled in the main loop if and
|
||||
* only if it is not threaded */
|
||||
if (client->bad)
|
||||
{
|
||||
/*send (client->handle, i, "INTERNAL SERVER ERROR..", ...);*/
|
||||
/*shutdown (client->handle.i, SHUT_RDWR);*/
|
||||
|
||||
/*pthread_mutex_lock (&httpd->client.mutex);*/
|
||||
delete_from_client_array (httpd, fd);
|
||||
/*pthread_mutex_unlock (&httpd->client.mutex);*/
|
||||
}
|
||||
else if (client->task.queue.count > 0)
|
||||
{
|
||||
if (client->task.queue.head->task.trigger.i <= -1 ||
|
||||
FD_ISSET(client->task.queue.head->task.trigger.i, &r))
|
||||
{
|
||||
perform_task (httpd, client);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if (!httpd->threaded)
|
||||
{
|
||||
if (client->bad)
|
||||
@ -1018,7 +1023,7 @@ qse_fprintf (QSE_STDERR, QSE_T("Error: select returned failure\n"));
|
||||
delete_from_client_array (httpd, fd);
|
||||
/*pthread_mutex_unlock (&httpd->client.mutex);*/
|
||||
}
|
||||
else if (client->task.queue.count > 0)
|
||||
else if (client->task.queue.head)
|
||||
{
|
||||
if (client->task.queue.head->task.trigger.i <= -1 ||
|
||||
FD_ISSET(client->task.queue.head->task.trigger.i, &r))
|
||||
@ -1027,7 +1032,7 @@ qse_fprintf (QSE_STDERR, QSE_T("Error: select returned failure\n"));
|
||||
tv.tv_usec = 0;
|
||||
FD_ZERO (&w);
|
||||
FD_SET (client->handle.i, &w);
|
||||
n = select (max + 1, QSE_NULL, &w, QSE_NULL, &tv);
|
||||
n = select (client->handle.i + 1, QSE_NULL, &w, QSE_NULL, &tv);
|
||||
|
||||
/* TODO: logging if n == -1 */
|
||||
|
||||
@ -1036,8 +1041,6 @@ qse_fprintf (QSE_STDERR, QSE_T("Error: select returned failure\n"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------*/
|
||||
}
|
||||
}
|
||||
|
||||
@ -1047,6 +1050,8 @@ qse_fprintf (QSE_STDERR, QSE_T("Error: select returned failure\n"));
|
||||
pthread_join (response_thread_id, QSE_NULL);
|
||||
pthread_cond_destroy (&httpd->client.cond);
|
||||
pthread_mutex_destroy (&httpd->client.mutex);
|
||||
QSE_CLOSE (httpd->client.pfd[1]);
|
||||
QSE_CLOSE (httpd->client.pfd[0]);
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -1287,7 +1292,15 @@ qse_httpd_task_t* qse_httpd_entask (
|
||||
ret = enqueue_task_locked (httpd, client, pred, task, xtnsize);
|
||||
if (ret == QSE_NULL) client->bad = 1; /* mark this client bad */
|
||||
#if defined(HAVE_PTHREAD)
|
||||
else if (httpd->threaded) pthread_cond_signal (&httpd->client.cond);
|
||||
else if (httpd->threaded)
|
||||
{
|
||||
static qse_byte_t dummy = 0x01;
|
||||
/* write to the pipe to wake up select() in
|
||||
* the response thread if it was blocking. */
|
||||
QSE_WRITE (httpd->client.pfd[1], &dummy, 1);
|
||||
|
||||
pthread_cond_signal (&httpd->client.cond);
|
||||
}
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
|
@ -114,11 +114,13 @@ struct qse_httpd_t
|
||||
|
||||
int option;
|
||||
int stopreq;
|
||||
|
||||
int threaded;
|
||||
|
||||
struct
|
||||
{
|
||||
#if defined(HAVE_PTHREAD)
|
||||
int pfd[2];
|
||||
pthread_mutex_t mutex;
|
||||
pthread_cond_t cond;
|
||||
#endif
|
||||
@ -149,6 +151,7 @@ void qse_httpd_fini (
|
||||
qse_httpd_t* httpd
|
||||
);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@ -1622,7 +1622,9 @@ qse_printf (QSE_T("CGI FUCKED UP...RETURNING TOO MUCH DATA\n"));
|
||||
return -1;
|
||||
}
|
||||
|
||||
#if 0
|
||||
qse_printf (QSE_T("CGI SEND [%.*hs]\n"), (int)cgi->buflen, cgi->buf);
|
||||
#endif
|
||||
n = send (client->handle.i, cgi->buf, cgi->buflen, 0);
|
||||
if (n <= -1)
|
||||
{
|
||||
@ -1634,7 +1636,9 @@ qse_printf (QSE_T("CGI SEND [%.*hs]\n"), (int)cgi->buflen, cgi->buf);
|
||||
QSE_MEMCPY (&cgi->buf[0], &cgi->buf[n], cgi->buflen - n);
|
||||
cgi->buflen -= n;
|
||||
|
||||
#if 0
|
||||
qse_printf (QSE_T("CGI SEND DONE\n"));
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -37,7 +37,8 @@ static int handle_request (
|
||||
#endif
|
||||
|
||||
qse_printf (QSE_T("================================\n"));
|
||||
qse_printf (QSE_T("REQUEST ==> [%hs] version[%d.%d] method[%d]\n"),
|
||||
qse_printf (QSE_T("[%lu] REQUEST ==> [%hs] version[%d.%d] method[%d]\n"),
|
||||
(unsigned long)time(NULL),
|
||||
qse_htre_getqpathptr(req),
|
||||
qse_htre_getmajorversion(req),
|
||||
qse_htre_getminorversion(req),
|
||||
|
Loading…
Reference in New Issue
Block a user