1ed6f5d66Smrg/*
2ed6f5d66Smrg * Copyright © 2013 Keith Packard
3ed6f5d66Smrg *
4ed6f5d66Smrg * Permission to use, copy, modify, distribute, and sell this software and its
5ed6f5d66Smrg * documentation for any purpose is hereby granted without fee, provided that
6ed6f5d66Smrg * the above copyright notice appear in all copies and that both that copyright
7ed6f5d66Smrg * notice and this permission notice appear in supporting documentation, and
8ed6f5d66Smrg * that the name of the copyright holders not be used in advertising or
9ed6f5d66Smrg * publicity pertaining to distribution of the software without specific,
10ed6f5d66Smrg * written prior permission.  The copyright holders make no representations
11ed6f5d66Smrg * about the suitability of this software for any purpose.  It is provided "as
12ed6f5d66Smrg * is" without express or implied warranty.
13ed6f5d66Smrg *
14ed6f5d66Smrg * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
15ed6f5d66Smrg * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
16ed6f5d66Smrg * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
17ed6f5d66Smrg * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
18ed6f5d66Smrg * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
19ed6f5d66Smrg * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
20ed6f5d66Smrg * OF THIS SOFTWARE.
21ed6f5d66Smrg */
22ed6f5d66Smrg
23ed6f5d66Smrg#if HAVE_CONFIG_H
24ed6f5d66Smrg#include "config.h"
25ed6f5d66Smrg#endif
26ed6f5d66Smrg
27ed6f5d66Smrg#include "xshmfenceint.h"
28ed6f5d66Smrg
2953bb355aSmrg#include <fcntl.h>
3053bb355aSmrg
31ed6f5d66Smrg#if !HAVE_MEMFD_CREATE
32ed6f5d66Smrg#if HAVE_DECL___NR_MEMFD_CREATE
33ed6f5d66Smrg#include <asm/unistd.h>
34ed6f5d66Smrgstatic int memfd_create(const char *name,
35ed6f5d66Smrg			    unsigned int flags)
36ed6f5d66Smrg{
37ed6f5d66Smrg	return syscall(__NR_memfd_create, name, flags);
38ed6f5d66Smrg}
39ed6f5d66Smrg#define HAVE_MEMFD_CREATE	1
40ed6f5d66Smrg#endif
41ed6f5d66Smrg#endif
42ed6f5d66Smrg
43ed6f5d66Smrg#if HAVE_MEMFD_CREATE
44ed6f5d66Smrg
45ed6f5d66Smrg/* Get defines for the memfd_create syscall, using the
46ed6f5d66Smrg * header if available, or just defining the constants otherwise
47ed6f5d66Smrg */
48ed6f5d66Smrg
49ed6f5d66Smrg#if HAVE_MEMFD_H
50ed6f5d66Smrg#include <sys/memfd.h>
51ed6f5d66Smrg#else
52ed6f5d66Smrg/* flags for memfd_create(2) (unsigned int) */
53ed6f5d66Smrg#define MFD_CLOEXEC		0x0001U
54ed6f5d66Smrg#define MFD_ALLOW_SEALING	0x0002U
55ed6f5d66Smrg#endif
56ed6f5d66Smrg
57ed6f5d66Smrg#endif
58ed6f5d66Smrg
59ed6f5d66Smrg/**
60ed6f5d66Smrg * xshmfence_alloc_shm:
61ed6f5d66Smrg *
62ed6f5d66Smrg * Allocates a shared memory object large enough to hold a single
63ed6f5d66Smrg * fence.
64ed6f5d66Smrg *
65ed6f5d66Smrg * Return value: the file descriptor of the object, or -1 on failure
66ed6f5d66Smrg * (in which case, errno will be set as appropriate).
67ed6f5d66Smrg **/
68ed6f5d66Smrgint
69ed6f5d66Smrgxshmfence_alloc_shm(void)
70ed6f5d66Smrg{
71ed6f5d66Smrg	char	template[] = SHMDIR "/shmfd-XXXXXX";
72ed6f5d66Smrg	int	fd;
7353bb355aSmrg#ifndef HAVE_MKOSTEMP
7453bb355aSmrg	int	flags;
7553bb355aSmrg#endif
76ed6f5d66Smrg
77ed6f5d66Smrg#if HAVE_MEMFD_CREATE
78ed6f5d66Smrg	fd = memfd_create("xshmfence", MFD_CLOEXEC|MFD_ALLOW_SEALING);
79ed6f5d66Smrg	if (fd < 0)
8053bb355aSmrg#endif
8153bb355aSmrg#ifdef SHM_ANON
8253bb355aSmrg	fd = shm_open(SHM_ANON, O_RDWR|O_CLOEXEC, 0600);
8353bb355aSmrg	if (fd < 0)
84ed6f5d66Smrg#endif
85ed6f5d66Smrg	{
86ed6f5d66Smrg#ifdef O_TMPFILE
87ed6f5d66Smrg		fd = open(SHMDIR, O_TMPFILE|O_RDWR|O_CLOEXEC|O_EXCL, 0666);
88ed6f5d66Smrg		if (fd < 0)
89ed6f5d66Smrg#endif
90ed6f5d66Smrg		{
9153bb355aSmrg#ifdef HAVE_MKOSTEMP
9253bb355aSmrg			fd = mkostemp(template, O_CLOEXEC);
9353bb355aSmrg#else
94ed6f5d66Smrg			fd = mkstemp(template);
9553bb355aSmrg#endif
96ed6f5d66Smrg			if (fd < 0)
97ed6f5d66Smrg				return fd;
98ed6f5d66Smrg			unlink(template);
9953bb355aSmrg#ifndef HAVE_MKOSTEMP
10053bb355aSmrg			flags = fcntl(fd, F_GETFD);
10153bb355aSmrg			if (flags != -1) {
10253bb355aSmrg				flags |= FD_CLOEXEC;
10353bb355aSmrg				fcntl(fd, F_SETFD, &flags);
10453bb355aSmrg			}
10553bb355aSmrg#endif
106ed6f5d66Smrg		}
107ed6f5d66Smrg	}
108ed6f5d66Smrg	if (ftruncate(fd, sizeof (struct xshmfence)) < 0) {
109ed6f5d66Smrg            close(fd);
110ed6f5d66Smrg            return -1;
111ed6f5d66Smrg        }
112ed6f5d66Smrg        xshmfence_init(fd);
113ed6f5d66Smrg	return fd;
114ed6f5d66Smrg}
115ed6f5d66Smrg
116ed6f5d66Smrg/**
117ed6f5d66Smrg * xshmfence_map_shm:
118ed6f5d66Smrg *
119ed6f5d66Smrg * Map a shared memory fence referenced by @fd.
120ed6f5d66Smrg *
121ed6f5d66Smrg * Return value: the fence or NULL (in which case, errno will be set
122ed6f5d66Smrg * as appropriate).
123ed6f5d66Smrg **/
124ed6f5d66Smrgstruct xshmfence *
125ed6f5d66Smrgxshmfence_map_shm(int fd)
126ed6f5d66Smrg{
127ed6f5d66Smrg	struct xshmfence *addr;
128ed6f5d66Smrg	addr = mmap (NULL, sizeof (struct xshmfence) , PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
129ed6f5d66Smrg	if (addr == MAP_FAILED) {
130ed6f5d66Smrg		close (fd);
131ed6f5d66Smrg		return 0;
132ed6f5d66Smrg	}
133875bea1aSmrg#ifdef HAVE_SEMAPHORE
134875bea1aSmrg	xshmfence_open_semaphore(addr);
135875bea1aSmrg#endif
136ed6f5d66Smrg	return addr;
137ed6f5d66Smrg}
138ed6f5d66Smrg
139ed6f5d66Smrg/**
140ed6f5d66Smrg * xshmfence_unmap_shm:
141ed6f5d66Smrg *
142ed6f5d66Smrg * Unap a shared memory fence @f.
143ed6f5d66Smrg **/
144ed6f5d66Smrgvoid
145ed6f5d66Smrgxshmfence_unmap_shm(struct xshmfence *f)
146ed6f5d66Smrg{
147875bea1aSmrg#ifdef HAVE_SEMAPHORE
148875bea1aSmrg	xshmfence_close_semaphore(f);
149875bea1aSmrg#endif
150ed6f5d66Smrg        munmap(f, sizeof (struct xshmfence));
151ed6f5d66Smrg}
152