//my_pxsem_mmap/sem_open.c
#include	"unpipc.h"
#include	"semaphore.h"

#include	<stdarg.h>		/*      */
#define		MAX_TRIES	10	/*    */

mysem_t	*
mysem_open(const char *pathname, int oflag, ... )
{
	int		fd, i, created, save_errno;
	mode_t	mode;
	va_list	ap;
	mysem_t	*sem, seminit;
	struct stat	statbuff;
	unsigned int	value;
	pthread_mutexattr_t	mattr;
	pthread_condattr_t	cattr;

	created = 0;
	sem = MAP_FAILED;				/* [sic] */
again:
	if (oflag & O_CREAT) {
		va_start(ap, oflag);		/* ap      */
		mode = va_arg(ap, va_mode_t) & ~S_IXUSR;
		value = va_arg(ap, unsigned int);
		va_end(ap);

			/*     O_EXCL    user-execute */
		fd = open(pathname, oflag | O_EXCL | O_RDWR, mode | S_IXUSR);
		if (fd < 0) {
			if (errno == EEXIST && (oflag & O_EXCL) == 0)
				goto exists;		/*  , OK */
			else
				return(SEM_FAILED);
		}
		created = 1;
			/*   ,     */
			/*    */
		bzero(&seminit, sizeof(seminit));
		if (write(fd, &seminit, sizeof(seminit)) != sizeof(seminit))
			goto err;

			/*     */
		sem = mmap(NULL, sizeof(mysem_t), PROT_READ | PROT_WRITE,
				   MAP_SHARED, fd, 0);
		if (sem == MAP_FAILED)
			goto err;

			/*   ,  ,   */
		if ( (i = pthread_mutexattr_init(&mattr)) != 0)
			goto pthreaderr;
		pthread_mutexattr_setpshared(&mattr, PTHREAD_PROCESS_SHARED);
		i = pthread_mutex_init(&sem->sem_mutex, &mattr);
		pthread_mutexattr_destroy(&mattr);	/*    */
		if (i != 0)
			goto pthreaderr;

		if ( (i = pthread_condattr_init(&cattr)) != 0)
			goto pthreaderr;
		pthread_condattr_setpshared(&cattr, PTHREAD_PROCESS_SHARED);
		i = pthread_cond_init(&sem->sem_cond, &cattr);
		pthread_condattr_destroy(&cattr);	/*    */
		if (i != 0)
			goto pthreaderr;

		if ( (sem->sem_count = value) > sysconf(_SC_SEM_VALUE_MAX)) {
			errno = EINVAL;
			goto err;
		}
			/*  ,   user-execute */
		if (fchmod(fd, mode) == -1)
			goto err;
		close(fd);
		sem->sem_magic = SEM_MAGIC;
		return(sem);
	}
