| /**************************************************************************** |
| * sched/sem_open.c |
| * |
| * Copyright (C) 2007, 2008 Gregory Nutt. All rights reserved. |
| * Author: Gregory Nutt <spudmonkey@racsa.co.cr> |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions |
| * are met: |
| * |
| * 1. Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * 2. Redistributions in binary form must reproduce the above copyright |
| * notice, this list of conditions and the following disclaimer in |
| * the documentation and/or other materials provided with the |
| * distribution. |
| * 3. Neither the name NuttX nor the names of its contributors may be |
| * used to endorse or promote products derived from this software |
| * without specific prior written permission. |
| * |
| * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS |
| * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE |
| * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, |
| * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, |
| * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS |
| * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED |
| * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
| * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN |
| * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
| * POSSIBILITY OF SUCH DAMAGE. |
| * |
| ****************************************************************************/ |
| |
| /**************************************************************************** |
| * Included Files |
| ****************************************************************************/ |
| |
| #include <nuttx/config.h> |
| |
| #include <sys/types.h> |
| #include <stdbool.h> |
| #include <stdarg.h> |
| #include <limits.h> |
| #include <fcntl.h> |
| #include <string.h> |
| #include <semaphore.h> |
| #include <errno.h> |
| #include <nuttx/kmalloc.h> |
| #include "sem_internal.h" |
| |
| /**************************************************************************** |
| * Pre-processor Definitions |
| ****************************************************************************/ |
| |
| /**************************************************************************** |
| * Private Type Declarations |
| ****************************************************************************/ |
| |
| /**************************************************************************** |
| * Global Variables |
| ****************************************************************************/ |
| |
| /**************************************************************************** |
| * Private Variables |
| ****************************************************************************/ |
| |
| /**************************************************************************** |
| * Private Functions |
| ****************************************************************************/ |
| |
| /**************************************************************************** |
| * Public Functions |
| ****************************************************************************/ |
| |
| /**************************************************************************** |
| * Function: sem_open |
| * |
| * Description: |
| * This function establishes a connection between named semaphores and a |
| * task. Following a call to sem_open() with the semaphore name, the task |
| * may reference the semaphore associated with name using the address |
| * returned by this call. The semaphore may be used in subsequent calls |
| * to sem_wait(), sem_trywait(), and sem_post(). The semaphore remains |
| * usable until the semaphore is closed by a successful call to sem_close(). |
| * |
| * If a task makes multiple calls to sem_open() with the same name, then |
| * the same semaphore address is returned (provided there have been no |
| * calls to sem_unlink()). |
| * |
| * Parameters: |
| * name - Semaphore name |
| * oflag - Semaphore creation options. This may either or both of the |
| * following bit settings. |
| * oflag = 0: Connect to the semaphore only if it already exists. |
| * oflag = O_CREAT: Connect to the semaphore if it exists, otherwise |
| * create the semaphore. |
| * oflag = O_CREAT|O_EXCL: Create a new semaphore |
| * unless one of this name already exists. |
| * Optional parameters. When the O_CREAT flag is specified, two optional |
| * parameters are expected: |
| * 1. mode_t mode (ignored), and |
| * 2. unsigned int value. This initial value of the semaphore. Valid |
| * initial values of the semaphore must be less than or equal to |
| * SEM_VALUE_MAX. |
| * |
| * Return Value: |
| * A pointer to sem_t or -1 (ERROR) if unsuccessful. |
| * |
| * Assumptions: |
| * |
| ****************************************************************************/ |
| |
| FAR sem_t *sem_open (FAR const char *name, int oflag, ...) |
| { |
| int namelen; |
| FAR nsem_t *psem; |
| FAR sem_t *sem = (FAR sem_t*)ERROR; |
| va_list arg; /* Points to each un-named argument */ |
| mode_t mode; /* Creation mode parameter (ignored) */ |
| unsigned int value; /* Semaphore value parameter */ |
| |
| /* Make sure that a non-NULL name is supplied */ |
| |
| if (name) |
| { |
| /* The POSIX specification requires that the "check for the |
| * existence of a semaphore and the creation of the semaphore |
| * if it does not exist shall be atomic with respect to other |
| * processes executing sem_open()..." A simple sched_lock() |
| * should be sufficient to meet this requirement. |
| */ |
| |
| sched_lock(); |
| namelen = strlen(name); |
| if (namelen > 0) |
| { |
| /* See if the semaphore already exists */ |
| |
| psem = sem_findnamed(name); |
| if (psem) |
| { |
| /* It does. Check if the caller wanted to created |
| * a new semahore with this name. |
| */ |
| |
| if (!(oflag & O_CREAT) || !(oflag & O_EXCL)) |
| { |
| /* Allow a new connection to the semaphore */ |
| |
| psem->nconnect++; |
| sem = &psem->sem; |
| } |
| } |
| |
| /* It doesn't exist. Should we create one? */ |
| |
| else if ((oflag & O_CREAT) != 0) |
| { |
| /* Set up to get the optional arguments needed to create |
| * a message queue. |
| */ |
| |
| va_start(arg, oflag); |
| mode = va_arg(arg, mode_t); |
| value = va_arg(arg, unsigned int); |
| |
| /* Verify that a legal initial value was selected. */ |
| |
| if (value <= SEM_VALUE_MAX) |
| { |
| /* Allocate memory for the new semaphore */ |
| |
| psem = (FAR nsem_t*)kmalloc((sizeof(nsem_t) + namelen + 1)); |
| if (psem) |
| { |
| /* Initialize the named semaphore */ |
| |
| sem = &psem->sem; |
| sem_init(sem, 0, value); |
| |
| psem->nconnect = 1; |
| psem->unlinked = false; |
| psem->name = (FAR char*)psem + sizeof(nsem_t); |
| strcpy(psem->name, name); |
| |
| /* Add the new semaphore to the list of named |
| * semaphores |
| */ |
| |
| dq_addfirst((FAR dq_entry_t*)psem, &g_nsems); |
| } |
| |
| /* Clean-up variable argument stuff */ |
| |
| va_end(arg); |
| } |
| } |
| } |
| sched_unlock(); |
| } |
| |
| return sem; |
| } |
| |