2013/10/26 Ted Unangst <[email protected]>:
> This may or may not be a working implementation of sem_open.
>
> Using tricks similar to those used in shm_open, we create a semaphore
> in a tmp file shared by mmap. This lets other processes share the
> spinlock and counter. Our thrsleep and thrwakeup syscalls don't really
> work between processes, so we have to synchronize all processes on the
> same in kernel address. This will cause spurious wakeups, but it
> shouldn't be the end of the world for light use.
>
> Index: sys/kern/kern_synch.c
> ===================================================================
> RCS file: /cvs/src/sys/kern/kern_synch.c,v
> retrieving revision 1.108
> diff -u -p -r1.108 kern_synch.c
> --- sys/kern/kern_synch.c       14 Sep 2013 01:35:01 -0000      1.108
> +++ sys/kern/kern_synch.c       25 Oct 2013 20:20:47 -0000
> @@ -419,6 +419,7 @@ thrsleep_unlock(void *lock, int lockflag
>         return (error);
>  }
>
> +static int magicnumber;
>
>  int
>  thrsleep(struct proc *p, struct sys___thrsleep_args *v)
> @@ -482,9 +483,13 @@ thrsleep(struct proc *p, struct sys___th
>
>         if (p->p_thrslpid == 0)
>                 error = 0;
> -       else
> -               error = tsleep(&p->p_thrslpid, PUSER | PCATCH, "thrsleep",
> +       else {
> +               void *sleepaddr = &p->p_thrslpid;
> +               if (ident == -1)
> +                       sleepaddr = &magicnumber;
> +               error = tsleep(sleepaddr, PUSER | PCATCH, "thrsleep",
>                     (int)to_ticks);
> +       }
>
>  out:
>         p->p_thrslpid = 0;
> @@ -535,6 +540,8 @@ sys___thrwakeup(struct proc *p, void *v,
>
>         if (ident == 0)
>                 *retval = EINVAL;
> +       else if (ident == -1)
> +               wakeup(&magicnumber);
>         else {
>                 TAILQ_FOREACH(q, &p->p_p->ps_threads, p_thr_link) {
>                         if (q->p_thrslpid == ident) {
> Index: lib/librthread/rthread.h
> ===================================================================
> RCS file: /cvs/src/lib/librthread/rthread.h,v
> retrieving revision 1.45
> diff -u -p -r1.45 rthread.h
> --- lib/librthread/rthread.h    21 Jun 2013 06:08:50 -0000      1.45
> +++ lib/librthread/rthread.h    25 Oct 2013 20:20:47 -0000
> @@ -64,7 +64,7 @@ struct __sem {
>         struct _spinlock lock;
>         volatile int waitcount;
>         volatile int value;
> -       int __pad;
> +       struct __sem *shared;
>  };
>
>  TAILQ_HEAD(pthread_queue, pthread);
> Index: lib/librthread/rthread_sem.c
> ===================================================================
> RCS file: /cvs/src/lib/librthread/rthread_sem.c,v
> retrieving revision 1.9
> diff -u -p -r1.9 rthread_sem.c
> --- lib/librthread/rthread_sem.c        1 Jun 2013 23:06:26 -0000       1.9
> +++ lib/librthread/rthread_sem.c        25 Oct 2013 20:20:47 -0000
> @@ -1,6 +1,6 @@
>  /*     $OpenBSD: rthread_sem.c,v 1.9 2013/06/01 23:06:26 tedu Exp $ */
>  /*
> - * Copyright (c) 2004,2005 Ted Unangst <[email protected]>
> + * Copyright (c) 2004,2005,2013 Ted Unangst <[email protected]>
>   * All Rights Reserved.
>   *
>   * Permission to use, copy, modify, and distribute this software for any
> @@ -15,15 +15,25 @@
>   * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
>   * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
>   */
> +#include <sys/param.h>
> +#include <sys/types.h>
> +#include <sys/mman.h>
> +#include <sys/stat.h>
>
> +#include <errno.h>
> +#include <fcntl.h>
> +#include <sha2.h>
>  #include <stdlib.h>
> +#include <stdio.h>
> +#include <string.h>
>  #include <unistd.h>
> -#include <errno.h>
>
>  #include <pthread.h>
>
>  #include "rthread.h"
>
> +#define SHARED_IDENT ((void *)-1)
> +
>  /*
>   * Internal implementation of semaphores
>   */
> @@ -31,8 +41,14 @@ int
>  _sem_wait(sem_t sem, int tryonly, const struct timespec *abstime,
>      int *delayed_cancel)
>  {
> +       void *ident = (void *)&sem->waitcount;
>         int r;
>
> +       if (sem->shared) {
> +               sem = sem->shared;
> +               ident = SHARED_IDENT;
> +       }
> +
>         _spinlock(&sem->lock);
>         if (sem->value) {
>                 sem->value--;
> @@ -42,7 +58,7 @@ _sem_wait(sem_t sem, int tryonly, const
>         } else {
>                 sem->waitcount++;
>                 do {
> -                       r = __thrsleep(&sem->waitcount, CLOCK_REALTIME |
> +                       r = __thrsleep(ident, CLOCK_REALTIME |
>                             _USING_TICKETS, abstime, &sem->lock.ticket,
>                             delayed_cancel);
>                         _spinlock(&sem->lock);
> @@ -63,12 +79,18 @@ _sem_wait(sem_t sem, int tryonly, const
>  int
>  _sem_post(sem_t sem)
>  {
> +       void *ident = (void *)&sem->waitcount;
>         int rv = 0;
>
> +       if (sem->shared) {
> +               sem = sem->shared;
> +               ident = SHARED_IDENT;
> +       }
> +
>         _spinlock(&sem->lock);
>         sem->value++;
>         if (sem->waitcount) {
> -               __thrwakeup(&sem->waitcount, 1);
> +               __thrwakeup(ident, 1);
>                 rv = 1;
>         }
>         _spinunlock(&sem->lock);
> @@ -136,6 +158,9 @@ sem_getvalue(sem_t *semp, int *sval)
>                 return (-1);
>         }
>
> +       if (sem->shared)
> +               sem = sem->shared;
> +
>         _spinlock(&sem->lock);
>         *sval = sem->value;
>         _spinunlock(&sem->lock);
> @@ -227,27 +252,88 @@ sem_trywait(sem_t *semp)
>         return (0);
>  }
>
> -/* ARGSUSED */
> +
> +/* SHA256_DIGEST_STRING_LENGTH includes nul */
> +/* "/tmp/" + sha256 + ".sem" */

Shouldn't this respect the TMPDIR envvar?

> +#define SEM_PATH_SIZE (5 + SHA256_DIGEST_STRING_LENGTH + 4)
> +
> +static void
> +makesempath(const char *origpath, char *sempath, size_t len)
> +{
> +       char buf[SHA256_DIGEST_STRING_LENGTH];
> +
> +       SHA256Data(origpath, strlen(origpath), buf);
> +       snprintf(sempath, len, "/tmp/%s.sem", buf);
> +}
> +
>  sem_t *
> -sem_open(const char *name __unused, int oflag __unused, ...)
> +sem_open(const char *name, int oflag, ...)
>  {
> -       errno = ENOSYS;
> -       return (SEM_FAILED);
> +       char sempath[SEM_PATH_SIZE];
> +       struct stat sb;
> +       int fd;
> +       sem_t sem, shared;
> +       sem_t *semp = SEM_FAILED;
> +       int len = PAGE_SIZE;
> +
> +       if (oflag & ~(O_CREAT | O_EXCL)) {
> +               errno = EINVAL;
> +               return semp;
> +       }
> +
> +       makesempath(name, sempath, sizeof(sempath));
> +       fd = open(sempath, O_RDWR | O_NOFOLLOW | oflag, 0600);
> +       if (fd == -1)
> +               return semp;
> +       if (fstat(fd, &sb) == -1 || !S_ISREG(sb.st_mode)) {
> +               close(fd);
> +               errno = EINVAL;
> +               return semp;
> +       }
> +       if (sb.st_uid != getuid()) {
> +               close(fd);
> +               errno = EPERM;
> +               return semp;
> +       }
> +       if (sb.st_size < len)
> +               ftruncate(fd, len);
> +       shared = mmap(NULL, len, PROT_READ | PROT_WRITE,
> +           MAP_FILE | MAP_SHARED | MAP_HASSEMAPHORE, fd, 0);
> +       close(fd);
> +       if (shared == MAP_FAILED)
> +               return semp;
> +       semp = malloc(sizeof(*semp));
> +       sem = calloc(1, sizeof(*sem));
> +       if (!semp || !sem) {
> +               munmap(shared, len);
> +               return SEM_FAILED;
> +       }
> +       *semp = sem;
> +       sem->shared = shared;
> +
> +       return semp;
> +
>  }
>
> -/* ARGSUSED */
>  int
> -sem_close(sem_t *sem __unused)
> +sem_close(sem_t *semp)
>  {
> -       errno = ENOSYS;
> -       return (-1);
> +       sem_t sem = *semp;
> +       int len = PAGE_SIZE;
> +
> +       munmap(sem->shared, len);
> +       free(sem);
> +       free(semp);
> +
> +       return (0);
>  }
>
> -/* ARGSUSED */
>  int
> -sem_unlink(const char *name __unused)
> +sem_unlink(const char *name)
>  {
> -       errno = ENOSYS;
> -       return (-1);
> +       char sempath[SEM_PATH_SIZE];
> +
> +       makesempath(name, sempath, sizeof(sempath));
> +       return unlink(sempath);
>  }
>
>
>

--
  WBR,
  Vadim Zhukov

Reply via email to