cURL / Mailing Lists / curl-library / Single Mail

curl-library

Re: mutex stuff

From: Daniel Stenberg <daniel_at_haxx.se>
Date: Thu, 21 Mar 2002 15:08:19 +0100 (MET)

On Thu, 21 Mar 2002, Noel Byron wrote:

(No longer posted to the curl-users list, only curl-library now.)

> > Did you check out the previous posts on this subject?
>
> A huge thread.

... and here comes another huge lump of text! ;-)

> I'm already through with my first 'proposal code'. That means I read your
> email to late. But I think we all have very similar thoughts.

That's good news. ;-)

> I have supplied a README in the attached archive that touches this question
> in the point: Design.

For the sake of the discussion on the list, I pasted your motivation here:

  - The user has to supply a create, a delete, a lock and a unlock callback.
    I added the first two because this gives libcURL the freedom to
    use as many different mutexes as necessary. I think this is very
    important since we can not know what additions will be made to libcURL
    in the Future.
  - I introduced a opaque curl_mutex_t. This is a struct in which the
    user can store everything that is needed for the mutexes.
  - The four functions are gathered in one struct.

I'll start with describing why I think the 'create' and 'delete' functions
are only adding complexity to libcurl:

* As I visiualize this, the callback coming from libcurl would include a
  "mutex identifier" (a simple enumerator, using 1, 2, 3 etc for the amount
  of mutexes we can come up with - new ones might be added in the future).
  That id would identify what mutex this particular lock call would concern.
  The application can implement one mutex for all identifiers, or one for
  each. Or none at all in fact, it can just pretend it has mutexes.

* This has the benefit from the library's point of view that it never has to
  create or delete any mutexes. We just have to add code that lock_mutex(id)
  first and then unlock_mutex(id). When we add a new mutex, we just add a new
  identifier and use that within the code.

* I do not want a solution that forces the application to actually make one
  native mutex for each mutex id that libcurl might use. That would impose
  much too strong restriction on the application for my taste. Imagine a
  system which has a limited number of mutexes.

* As most applications will *not* use mutexes, I believe in letting the
  complex things about mutexes get handled outside libcurl, by the app
  itself.

> The attachment curlthread.tar.gz:
>
> This is not a patch. It is a stand alone program with example code that
> should run out of the box with cygwin and Linux. But it should be easy to
> integrate it in libcURL. Just read the README...

I didn't quite see how your example program would fully apply to the
situation libcurl is in.

My way of adding this would put almost your entire code outside the libcurl
core:

Imagine that we define a new struct for setting up the mutex control in
libcurl (ignore the syntax, this is pseudo code to illustrate my point):

 struct curl_mutex1 {
   int version; /* set to a fixed define to be able to track changes in
                   the future */
   void *clientp; /* this pointer is passed to the callbacks */
   unlock(CURL *handle, curl_mutex_id id, void *clientp);
   lock(CURL *handle, curl_mutex_id id, void *clientp);
 };

In your particular program, you probably create all mutexes first and when
libcurl calls you, you just map the incoming id to whatever mutex you want to
use. If libcurl would call your function with an id you don't have a special
mutex for, you can have one single general-purpose mutex for "unknown ids".

You then enable mutex magic in libcurl similar to this:

 struct curl_mutex1 moootexx=
  {CURL_MUTEX_ONE, NULL, my_unlock, my_lock};

 curl_easy_setopt(easy, CURLOPT_MUTEX, &moootexx);

Now libcurl knows about mutexes, but there's no point in using mutexes unless
libcurl actually tries/wants to share something with another handle.

So we need to specify a) which handle to share "something" with, and b) what
to share with the handle:

 /* first set what kind of stuff we share among the handles specified
    after this */
 curl_easy_setopt(easy, CURLOPT_SHAREWHAT, CURL_SHARE_COOKIES);

 /* now "add" handles with which we share the former specified "goods" */
 curl_easy_setopt(easy, CURLOPT_SHARE, otherhandle);

... which then would make the two easy handles 'easy' and 'otherhandle' share
internal cookie stuff using the mutexes as setup in the moootexx struct.

(We would also need to add support for CURLOPT_UNSHARE so that you can remove
a share too from a handle.)

This latter stuff also goes pretty good together with the multi interface, as
when that is used, multiple transfers can go on and they can be made to share
all sorts of data without having to use mutexes when used single-threaded.

Phew. :-)

Again, these are my opinions and some of what I had envisioned. I am open for
discussions on different solutions to how this could/should be done. I am not
a dictator here. (I just wanted it said, I hope I haven't given that
impression.)

I might have misunderstood some arguments or reasons. Just keep repeating
them until I understand! ;-)

-- 
    Daniel Stenberg -- curl groks URLs -- http://curl.haxx.se/
Received on 2002-03-21