Re: light weight user level semaphores

Ulrich Drepper
2001-04-19T22:47:58Z

Linus Torvalds <torvalds@transmeta.com> writes:

> I'm not interested in re-creating the idiocies of Sys IPC.

I'm not talking about sysv semaphores (couldn't care less). And you
haven't read any of the mails with examples I sent.

If the new interface can be useful for anything it must allow to
implement process-shared POSIX mutexes. The user-level representation
of these mutexes are simple variables which in the case of
inter-process mutexes are placed in shared memory. These variables
must be usable with the normal pthread_mutex_lock() functions and
perform whatever is needed.

Whether the pthread_mutex_init() function for shared mutexes is doing
a lot more work and allocates even more memory, I don't care. The
standard certainly permits this and every pthread_mutex_init() must
have a pthread_mutex_destroy() which allows allocating and freeing
resources (no file descriptor, though). So, yes, your FS_create
syscall can allocate something.

But the question is what handle to put in the pthread_mutex_t variable
so the different processes can use the mutex. It cannot be a file
descriptor since it's not shared between processes. It cannot be a
pointer to some other place in the virtual memory since the place
pointed to might not be (and probably isn't if FS_create is allocating
something in the process setting up the mutex). You could put some
magic cookie in the pthread_mutex_t object the kernel can then use.

So, instead of repeating over and over again the same old story, fill
in the gaps here:

int
pthread_mutex_init (pthread_mutex_t *mutex,
const pthread_mutexattr_t *mutex_attr)
{
if (mutex_attr != NULL && mutex_attr->__pshared != 0)
{
... FILL IN HERE ...
}
else
...intra-process mutex, uninteresting here...
}

int
pthread_mutex_lock (pthread_mutex_t *mutex)
{
if (mutex_attr != NULL && mutex_attr->__pshared != 0)
{
... FILL IN HERE ...
}
else
...intra-process mutex, uninteresting here...
}

int
pthread_mutex_destroy (pthread_mutex_t *mutex)
{
if (mutex_attr != NULL && mutex_attr->__pshared != 0)
{
... FILL IN HERE ...
}
else
...intra-process mutex, uninteresting here...
}

These functions must work with something like this:

~~~~~~~~~~~~~~~~~~~~~ cons.c ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/mman.h>

int
main (int argc, char *argv[])
{
char tmpl[] = "/tmp/fooXXXXXX";
int fd = mkstemp (tmpl);
pthread_mutexattr_t attr;
pthread_mutex_t *m1;
pthread_mutex_t *m2;
void *addr;
volatile int *i;

pthread_mutexattr_init (&attr);
pthread_mutexattr_setpshared (&attr, PTHREAD_PROCESS_SHARED);

ftruncate (fd, 2 * sizeof (*m1) + sizeof (int));
addr = mmap (NULL, sizeof (*m1), PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
m1 = addr;
m2 = m1 + 1;
i = (int *) (m2 + 1);
*i = 0;

pthread_mutex_init (m1, &attr);
pthread_mutex_lock (m1);

pthread_mutex_init (m2, &attr);
pthread_mutex_lock (m2);

if (fork () == 0)
{
char buf[10];
snprintf (buf, sizeof buf, "%d", fd);
execl ("./prod", "prod", buf, NULL);
}

while (1)
{
pthread_mutex_lock (m1);
printf ("*i = %d\n", *i);
pthread_mutex_unlock (m2);
}

return 0;
}
~~~~~~~~~~~~~~~~~~~~~~prod.c ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/mman.h>

int
main (int argc, char *argv[])
{
int fd = atoi (argv[1]);
void *addr;
pthread_mutex_t *m1;
pthread_mutex_t *m2;
volatile int *i;

addr = mmap (NULL, sizeof (*m1), PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
m1 = addr;
m2 = m1 + 1;
i = (int *) (m2 + 1);

while (1)
{
++*i;
pthread_mutex_unlock (m1);
pthread_mutex_lock (m2);
}

return 0;
}
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

--
---------------. ,-. 1325 Chesapeake Terrace
Ulrich Drepper \ ,-------------------' \ Sunnyvale, CA 94089 USA
Red Hat `--' drepper at redhat.com `------------------------