[libmicrohttpd] Idea for a good design to use external select + suspend/resume + pthread

2019-03-16 Thread silvioprog
Hello everyone.

I've tried to use an external select, the suspend/resume feature and a
detached thread for some specific (slow) requests. The main idea around
this, is: the common requests (database CRUDs, html/js/css sending etc.)
are processed in the main loop within main thread (application), but, slow
requests (large report generation, remote backups etc.) are suspended to be
processed in a detached thread, which resumes the connection as soon as the
request processing ends. However, I have had some difficulty to solve
it because the MHD_queue_response() must be called by the main thread, not
by detached thread(s).

After some googling I found two good related topics:

1. https://lists.gnu.org/archive/html/libmicrohttpd/2016-09/msg0.html
2.
https://lists.endsoftwarepatents.org/archive/html/libmicrohttpd/2016-10/msg00011.html

The 1. is the same problem I'm trying to solve, but I wouldn't like to use
global variables. The 2. is exactly I'm looking for, but I couldn't find
any code/example showing how the problem was solved, so I suspect he used
the *con_cls instead of global variables to share some list reference to
the detached thread(s).

After reading these topics I got two doubts. It is a good practice to use a
shared vector (or any list + binary search) plus a mutex to manage each
detached thread? If so, could the same list be used to be iterated to call
the functions MHD_create_response_*() + MHD_queue_response() +
MHD_resume_connection() to dispatch their respective responses? I need to
take some care not to lose performance by choosing a bad design and, since
some members tried to solve the same problem, I decided to ask.

I have a draft (in attachment) which I'll use to start/try the design using
an external select + suspend/resume + pthread. It works fine if you
uncomment the macro INTERNAL_SELECT to use the internal MHD loop or the
macro TIMEOUT to use the external one. In this draft, the
MHD_queue_response() is called in the detached thread, it is wrong, but it
is just to understand how MHD works using external threads +
suspend/resume. If you keep both INTERNAL_SELECT and TIMEOUT commented, the
first request will never end unless another request arrives, I think a good
design should solve it.

I would appreciate any good idea about this. If solved, it would be nice to
convert it to a MHD example to share the solution for other members.

Thank you!

P.S.1: to test the draft above, use:

$ curl http://localhost: # simulates a common request.
$ curl http://localhost:/sleep # simulates a slow (about 10s) request.

P.S.2: I'm studying select()/epoll() and doing some exercises to fully
understand them.

-- 
Silvio Clécio
#include 
#include 
#include 
#include 
#include 
#include 

/*#define INTERNAL_SELECT 1*/

/*#define TIMEOUT 1*/

struct Request {
struct MHD_Connection *con;
char *url;
};

static void *
process_cb (void *cls)
{
  struct Request *req = cls;
  struct MHD_Response *res;
  const union MHD_ConnectionInfo *info;
  const char *msg = "hello";
  if (0 == strcmp (req->url, "/sleep"))
{
  usleep (1000 * 1000 * 10); /* Simulates a slow processing. */
  msg = "sleep";
}
  res = MHD_create_response_from_buffer (strlen (msg), (void *) msg,
 MHD_RESPMEM_PERSISTENT);
  MHD_queue_response (req->con, MHD_HTTP_OK, res);
  MHD_resume_connection (req->con);
  info = MHD_get_connection_info (req->con, MHD_CONNECTION_INFO_DAEMON);
  if (NULL != info)
MHD_run (info->daemon);
  MHD_destroy_response (res);
  free (req->url);
  free (req);
  pthread_exit (NULL);
}

static int
ahc_cb (void *cls,
struct MHD_Connection *con,
const char *url,
const char *method,
const char *version,
const char *upload_data,
size_t *upload_data_size,
void **ptr)
{
  struct Request *req;
  pthread_t thrd;
  (void) cls;   /* Unused. Silence compiler warning. */
  (void) method;/* Unused. Silence compiler warning. */
  (void) version;   /* Unused. Silence compiler warning. */
  (void) upload_data;   /* Unused. Silence compiler warning. */
  (void) upload_data_size;  /* Unused. Silence compiler warning. */
  if (NULL == *ptr)
{
  *ptr = (void *) 1;
  return MHD_YES;
}
  *ptr = NULL;
  MHD_suspend_connection (con);
  req = malloc (sizeof (struct Request));
  if (NULL == req)
return MHD_NO;
  req->con = con;
  req->url = strdup (url);
  if (NULL == req->url)
{
  free (req);
  return MHD_NO;
}
  if (0 != pthread_create (&thrd, NULL, process_cb, req))
{
  free (req->url);
  free (req);
  return MHD_NO;
}
  pthread_detach (thrd);
  return MHD_YES;
}

int
main (int argc,
  char *const *argv)
{
  struct MHD_Daemon *d;
  unsigned int flags = MHD_USE_SUSPEND_RESUME | MHD_USE_ERROR_LOG;
#ifndef INTERNAL_SELECT
  struct timeval tv;
  struct timeval *tvp;
  fd_set rs;
  fd_set ws;
  fd_set es;
  MHD_socket max;
  MHD_UNS

Re: [libmicrohttpd] Idea for a good design to use external select + suspend/resume + pthread

2019-03-16 Thread silvioprog
On Sun, Mar 17, 2019 at 2:28 AM silvioprog  wrote:

> ... It is a good practice ...
>

I meant "Is it a good practice ...".

--
Silvio Clécio