Optimus1
Optimus1

Reputation: 448

Libcurl - CURLSHOPT_LOCKFUNC - how to use it?

Please tell me the nuances of using the option CURLSHOPT_LOCKFUNC ?

I found an example here.

I can't quite understand, is there an array of mutexes used to block access to data?

--Here is this part of the code from the example:

static pthread_mutex_t lockarray[NUM_LOCKS];  Is it an array of mutexes ?
//.....
static void lock_cb(CURL *handle, curl_lock_data data,
                    curl_lock_access access, void *userptr)
{
  (void)access;
  (void)userptr;
  (void)handle;
  pthread_mutex_lock(&lockarray[data]);
}

That is, from this section of code - I can conclude that different mutexes are used to lock CURLSHOPT_LOCKFUNC ?

I don't understand how it is? Isn't there more than one mutex needed to synchronize threads to access data?

And this part of the code is also not clear:

pthread_mutex_lock(&lockarray[data]);

What kind of variable is data ?

The documentation says: https://curl.se/libcurl/c/CURLSHOPT_LOCKFUNC.html

The data argument tells what kind of data libcurl wants to lock. Make sure that the callback uses a different lock for each kind of data.

What means: "what kind of data libcurl wants to lock" ??

I can't understand.

Upvotes: 1

Views: 580

Answers (1)

Remy Lebeau
Remy Lebeau

Reputation: 597051

Yes, the code is using an array of mutexes.

curl_lock_data is an enum that is defined in curl.h and specifies the different types of data that curl uses locks for:

/* Different data locks for a single share */
typedef enum {
  CURL_LOCK_DATA_NONE = 0,
  /*  CURL_LOCK_DATA_SHARE is used internaly to say that
   *  the locking is just made to change the internal state of the share
   *  itself.
   */
  CURL_LOCK_DATA_SHARE, 
  CURL_LOCK_DATA_COOKIE,
  CURL_LOCK_DATA_DNS,
  CURL_LOCK_DATA_SSL_SESSION,
  CURL_LOCK_DATA_CONNECT,
  CURL_LOCK_DATA_LAST
 } curl_lock_data;

Since the values are sequential, the code is using them as indexes into the array.

So, for example, when multiple threads are accessing shared cookie data, they will lock/unlock the CURL_LOCK_DATA_COOKIE mutex.

curl_lock_access is another enum defined in curl.h, which specifies why a given lock is being obtained:

/* Different lock access types */
typedef enum {
  CURL_LOCK_ACCESS_NONE = 0,   /* unspecified action */
  CURL_LOCK_ACCESS_SHARED = 1, /* for read perhaps */
  CURL_LOCK_ACCESS_SINGLE = 2, /* for write perhaps */
  CURL_LOCK_ACCESS_LAST        /* never use */
} curl_lock_access;

The difference between these reasons doesn't matter for a mutex, which has only a notion of exclusive access, meaning only 1 thread at a time can hold the lock. That is why the code is not using the access parameter.

But, other types of locks, for instance a RW (reader/writer) lock, do have a concept of shared access (ie, multiple threads can hold the lock at the same time) vs exclusive access. When multiple threads want to access the same shared data for just reading only, it makes sense for them to not block each other. Only when a thread wants to modify the shared data should other threads then be blocked from accessing that data, for reading or writing, until the modification is finished.

For example:

const int NUM_LOCKS = CURL_LOCK_DATA_LAST + 1;
static pthread_rwlock_t lockarray[NUM_LOCKS];

...

static void lock_cb(CURL *handle, curl_lock_data data,
                    curl_lock_access access, void *userptr)
{
  (void)handle;
  (void)userptr;
  switch (access) {
    case CURL_LOCK_ACCESS_SHARED:
      pthread_rwlock_rdlock(&lockarray[data]);
      break;
    case CURL_LOCK_ACCESS_ SINGLE:
      pthread_rwlock_wrlock(&lockarray[data]);
      break;
  }
}

static void unlock_cb(CURL *handle, curl_lock_data data,
                    curl_lock_access access, void *userptr)
{
  (void)handle;
  (void)access;
  (void)userptr;
  pthread_rwlock_unlock(&lockarray[data]);
}

Upvotes: 2

Related Questions