/*[XSI]*/ /* Test whether a basic shmat invocation works. */ #include #include #include #include "../basic.h" #ifndef SHM_FAILED #define SHM_FAILED ((void*) -1) #endif // XSI IPC resources are system wide and have no proper namespace. If we lose // track of the id, there is no real way to know the purpose of the id, and // nothing can safely reclaim it. To avoid leaks, this test uses atexit to make // sure XSI IPC sources are cleaned up on process shutdown, and signal handlers // are used to clean up on SIGINT/SIGQUIT/SIGTERM. However, resources will leak // if the test crashes or is SIGKILL'd or otherwise abnormally terminated. static int shmid; static void cleanup(void) { sigset_t set, oldset; sigemptyset(&set); sigaddset(&set, SIGINT); sigaddset(&set, SIGQUIT); sigaddset(&set, SIGTERM); sigprocmask(SIG_BLOCK, &set, &oldset); if ( 0 < shmid ) shmctl(shmid, IPC_RMID, NULL); shmid = 0; sigprocmask(SIG_SETMASK, &set, NULL); } static void on_signal(int signo) { cleanup(); sigset_t set; sigemptyset(&set); sigaddset(&set, signo); raise(signo); // Make sure the signal is immediately pending on sigprocmask. sigprocmask(SIG_UNBLOCK, &set, NULL); raise(signo); // We should't end here, but try again. } int main(void) { if ( atexit(cleanup) ) err(1, "atexit"); struct sigaction sa = { .sa_handler = on_signal }; sigemptyset(&sa.sa_mask); sigaddset(&sa.sa_mask, SIGINT); sigaddset(&sa.sa_mask, SIGQUIT); sigaddset(&sa.sa_mask, SIGTERM); if ( sigaction(SIGINT, &sa, NULL) < 0 || sigaction(SIGQUIT, &sa, NULL) < 0 || sigaction(SIGTERM, &sa, NULL) < 0 ) err(1, "sigaction"); long pagesize = sysconf(_SC_PAGESIZE); if ( pagesize < 0 ) err(1, "sysconf _SC_PAGESIZE"); shmid = shmget(IPC_PRIVATE, pagesize, 0600); if ( shmid < 0 ) err(1, "shmget"); void* ptr = shmat(shmid, NULL, 0); if ( ptr == SHM_FAILED ) err(1, "shmat"); volatile char* buf = ptr; buf[0] = 'X'; return 0; }