diff options
author | Keith Packard <keithp@keithp.com> | 2014-01-30 12:25:32 -0800 |
---|---|---|
committer | Keith Packard <keithp@keithp.com> | 2014-01-30 12:25:32 -0800 |
commit | 2661e8f80aa20c695248d227778efa3593471df8 (patch) | |
tree | fadbcdecb02ef99591963054a7713f665f44ce7c | |
parent | 8c88e071c5cefa1559989d0292cdfba6b438793c (diff) |
Missing shmtest.c
Signed-off-by: Keith Packard <keithp@keithp.com>
-rw-r--r-- | shmtest.c | 134 |
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); +} |