Skip to content

Instantly share code, notes, and snippets.

@karthick18
Created December 3, 2010 19:40
Show Gist options
  • Save karthick18/727443 to your computer and use it in GitHub Desktop.
Save karthick18/727443 to your computer and use it in GitHub Desktop.
Useless rwlock wrapper with another useless upgrade to write
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <pthread.h>
typedef struct pthread_rwlock_wrapper
{
pthread_rwlock_t rwlock;
pthread_spinlock_t spinlock;
} pthread_rwlock_wrapper_t;
static __inline__ pthread_rwlock_t *pthread_rwlock_wrapper_alloc(void)
{
pthread_rwlock_wrapper_t *wrapper = calloc(1, sizeof *wrapper);
int err;
assert(wrapper);
err = pthread_rwlock_init(&wrapper->rwlock, NULL);
assert(err == 0);
err = pthread_spin_init(&wrapper->spinlock, PTHREAD_PROCESS_PRIVATE);
assert(err == 0);
return &wrapper->rwlock;
}
static __inline__ void pthread_rwlock_wrapper_free(pthread_rwlock_t *rwlock)
{
pthread_rwlock_wrapper_t *wrapper = (pthread_rwlock_wrapper_t*)rwlock;
assert(wrapper);
pthread_rwlock_destroy(&wrapper->rwlock);
pthread_spin_destroy(&wrapper->spinlock);
free(wrapper);
}
/*
* Should be called with readlock held. No use actually but just serializes multiple reader upgrades again redundant
* But the issue is still with rd unlock triggering a write wake which should have been an atomic nr_readers decrement
* in followed by wrlock atomically.
*/
static void pthread_rwlock_wrapper_upgrade_write(pthread_rwlock_t *rwlock)
{
pthread_rwlock_wrapper_t *wrapper = (pthread_rwlock_wrapper_t*)rwlock;
assert(wrapper);
pthread_spin_lock(&wrapper->spinlock);
pthread_rwlock_unlock(&wrapper->rwlock);
if(pthread_rwlock_trywrlock(&wrapper->rwlock))
{
pthread_spin_unlock(&wrapper->spinlock);
pthread_rwlock_wrlock(&wrapper->rwlock); /*retry the write lock*/
} else pthread_spin_unlock(&wrapper->spinlock);
}
/*
* Some useless usage-example. with a useless linked list (no generic list_heads here) using the upgrade write just to test
*/
struct list { struct list*next; void *data; } ;
static struct list *head;
static pthread_rwlock_t *g_rwlock;
static void add_list(void *data)
{
struct list *l = calloc(1, sizeof(*l));
assert(l);
l->data = data;
/*
* Want to comment this.
*/
pthread_rwlock_rdlock(g_rwlock);
pthread_rwlock_wrapper_upgrade_write(g_rwlock);
/*
* Want to comment this.
*/
//l->next = head;
//head = l;
l->next = __sync_val_compare_and_swap(&head, head, l); /* gcc builtin for CAS */
/*
* Want to comment this.
*/
pthread_rwlock_unlock(g_rwlock);
}
static void dump_list(void)
{
register struct list *iter;
pthread_rwlock_rdlock(g_rwlock);
for(iter = head; iter; iter = iter->next)
printf("Item = [%d]\n", *(int*)iter->data);
pthread_rwlock_unlock(g_rwlock);
}
static void *run_thread(void *arg)
{
int index = *(int*)arg * 10;
register int i;
for(i = index; i < index+10; ++i)
{
void *d = malloc(sizeof(i));
assert(d);
*(int*)d = i;
add_list(d);
}
return NULL;
}
int main(int argc, char **argv)
{
int i;
pthread_t tids[10];
g_rwlock = pthread_rwlock_wrapper_alloc();
for(i = 0; i < sizeof(tids)/sizeof(tids[0]); ++i)
{
int *r = malloc(sizeof(*r));
assert(r); *r = i;
pthread_create(&tids[i], NULL, run_thread, r);
}
for(i = 0; i < sizeof(tids)/sizeof(tids[0]); ++i)
pthread_join(tids[i], NULL);
dump_list();
pthread_rwlock_wrapper_free(g_rwlock);
return 0;
}
/*
* Local variables:
* c-file-style: "linux"
* compile-command: "gcc -Wall -g -o rwlock_wrapper rwlock_wrapper.c -std=c99 -pedantic -lpthread"
* tab-width: 4
* End:
*/
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment