summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKeith Packard <keithp@keithp.com>2014-01-30 12:25:32 -0800
committerKeith Packard <keithp@keithp.com>2014-01-30 12:25:32 -0800
commit2661e8f80aa20c695248d227778efa3593471df8 (patch)
treefadbcdecb02ef99591963054a7713f665f44ce7c
parent8c88e071c5cefa1559989d0292cdfba6b438793c (diff)
Missing shmtest.c
Signed-off-by: Keith Packard <keithp@keithp.com>
-rw-r--r--shmtest.c134
1 files changed, 134 insertions, 0 deletions
diff --git a/shmtest.c b/shmtest.c
new file mode 100644
index 0000000..0ec8a3c
--- /dev/null
+++ b/shmtest.c
@@ -0,0 +1,134 @@
+/*
+ * Copyright © 2013 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#include <stdio.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <sys/mman.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <signal.h>
+#include <fcntl.h>
+
+int
+make_shm(int size)
+{
+ char template[] = "/run/shm/shmfd-XXXXXX";
+ int fd = mkstemp(template);
+
+ if (fd < 0)
+ return fd;
+ unlink(template);
+ ftruncate(fd, size);
+ return fd;
+}
+
+void *
+map_shm(int fd, int size)
+{
+ void *addr;
+ addr = mmap (NULL, size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
+ if (addr == MAP_FAILED) {
+ close (fd);
+ exit(1);
+ }
+ return addr;
+}
+
+void
+paint(uint32_t *base, int width, int height, int forward)
+{
+ int x, y;
+ uint8_t r, g, b;
+
+ for (y = 0; y < height; y++) {
+ for (x = 0; x < width; x++) {
+ r = x * 256 / width;
+ g = 255 - r;
+ if (forward)
+ b = y * 256 / height;
+ else
+ b = (255 - y) * 256 / height;
+ base[y * width + x] = (r << 16) | (g << 8) | b;
+ }
+ }
+}
+
+#define WIDTH 128
+#define HEIGHT 128
+
+int parent_fd;
+void *parent_addr;
+int parent_size;
+void *fault_addr;
+
+void bus_handler(int sig, siginfo_t *info, void *param)
+{
+ int zero_fd;
+ void *ret;
+
+ fault_addr = info->si_addr;
+ write(2, "bus error\n", 10);
+ munmap(parent_addr, parent_size);
+ close(parent_fd);
+ zero_fd = open("/dev/zero", 2);
+
+ ret = mmap(parent_addr, parent_size, PROT_READ|PROT_WRITE, MAP_PRIVATE, zero_fd, 0);
+ if (ret != parent_addr) {
+ write(2, "bus remap failed\n", 18);
+ exit(1);
+ }
+ close(zero_fd);
+}
+
+int
+main (int argc, char **argv)
+{
+ int fd;
+ void *addr;
+ uint32_t size = WIDTH * HEIGHT * 4;
+ struct sigaction act;
+
+ fd = make_shm(size); /* some memory */
+
+ switch (fork()) {
+ case -1:
+ perror("fork failed");
+ exit(1);
+ case 0:
+ addr = map_shm(fd, size);
+ sleep(1);
+ ftruncate(fd, 0);
+ break;
+ default:
+ parent_fd = fd;
+ act.sa_sigaction = bus_handler;
+ act.sa_flags = SA_SIGINFO;
+ sigaction(SIGBUS, &act, NULL);
+ addr = map_shm(fd, size);
+ parent_addr = addr;
+ parent_size = size;
+ sleep(2);
+ paint(addr, WIDTH, HEIGHT, 0);
+ printf ("painted\n");
+ printf ("map addr: %p\n", addr);
+ printf ("fault addr: %p\n", fault_addr);
+ }
+ exit(0);
+}