cURL / Mailing Lists / curl-library / Single Mail

curl-library

Re: [PATCH] Call progress function when poll()/select() is interrupted

From: Yang Tse <yangsita_at_gmail.com>
Date: Wed, 16 Apr 2008 04:56:00 +0200

2008/4/16, Pierre Ynard wrote:

> So I will add a function like Curl_checkAbort(), which will basically
> call the user's progress callback, passing the current (old) state
> data, without doing all the costly updating stuff in Curl_pgrsUpdate().

Nope.

There has to be a _new_ user provided callback (abort check callback)
which somehow will find out and tell to libcurl if libcurl should
abort or not.

typedef int (*curl_abortcheck_callback)(void);

This 'abort check callback' should by no means block execution. It
could check the state of a global variable that could be set by a
signal handler. It could check the state of some IPC facility. There
are lots of possibilities here. The only restrictions are that it
_must_ not block and that it should not take too long to execute.

Since this callback must be kept libcurl_internal_agnostic, no
parameter would be needed for it (I hope so). libcurl would only care
about its return value.

> Curl_checkAbort() will be the function called before poll()/select()
> to help minimizing race conditions, since this call is unconditional
> and there should not be much pending to update there, right?

I know I've mentioned a potential Curl_checkAbort() but actually it
might not even be necessary. Before poll()/select() it would be enough
to verify if the user has 'installed' a callback for abort checking
and calling it when available. The following is closer to what I
actually mean for select.c...

  do {
    if(timeout_ms < 0)
      pending_ms = -1;
    else if(!timeout_ms)
      pending_ms = 0;

    if(timeout_ms && data->set.fabortcheck) {
      r = data->set.fabortcheck();
      if(r)
        r = CURL_CSELECT_ABORT;
        break;
    }

    r = poll(pfd, num, pending_ms);
    if(r != -1)
      break;
    error = SOCKERRNO;
    if(error && error_not_EINTR)
      break;

    if(Curl_pgrsUpdate(conn)) {
      r = CURL_CSELECT_ABORT;
      break;
    }

    if(timeout_ms > 0) {
      pending_ms = timeout_ms - elapsed_ms;
      if(pending_ms <= 0)
        break;
    }
  } while(r == -1);

And for progress.c something like...

int Curl_pgrsUpdate(struct connectdata *conn)
{
  struct timeval now;
  [...]
  struct SessionHandle *data = conn->data;
  [...]
  bool shownow=FALSE;

  if(data->set.fabortcheck) {
    r = data->set.fabortcheck();
    if(r) {
      failf(data, "Callback aborted");
      return CURL_CSELECT_ABORT;
    }
  }

  now = Curl_tvnow(); /* what time is it */

  [...]

> After and if poll()/select() is aborted, should I also only call this
> Curl_checkAbort(), or it is worth calling Curl_pgrsUpdate() this time?

If Curl_pgrsUpdate() starts as I propose above, then the call _could_
be to Curl_pgrsUpdate() as I've written much above, this in turn would
call fabortcheck() if set.

But your last question makes me think twice ;-)

It is true that here Curl_pgrsUpdate() would only get called when
poll()/select() is interrupted. But...when this happens...

Who knows which part of libcurl could be executing Curl_socket_ready()
or Curl_poll() ?

So, to stay on the safe side, I actually think that it is better to
call fabortcheck() instead of Curl_pgrsUpdate() once that
poll()/select() is interrupted. _And_ also keep the call to
fabortcheck() inside Curl_pgrsUpdate() so that it also benefits of the
new callback if the user has provided it.

-- 
-=[Yang]=-
Received on 2008-04-16