#include #include #include #include #include #include #include #include #include #include #define LARGE_SHARED_SEGMENT_KEY 0x12345600 #define LARGE_SHARED_SEGMENT_SIZE ((size_t)0x40000000) #define LARGE_SHARED_SEGMENT_ADDR ((void *)0x40000000) #define SMALL_SHARED_SEGMENT_KEY 0x12345601 #define SMALL_SHARED_SEGMENT_SIZE ((size_t)0x20000000) #define SMALL_SHARED_SEGMENT_ADDR ((void *)0x94000000) #define NUM_SMALL_BUFFERS 50 char *helper_program = "echo"; char *helper_args[] = { "-n", ".", NULL }; void child_signal_handler(const int unused) { int errno_save; pid_t dead_pid; int dead_status; errno_save = errno; do { dead_pid = waitpid(-1, &dead_status, WNOHANG); if (dead_pid == -1) { if (errno == ECHILD) break; perror("waitpid"); exit(EXIT_FAILURE); } } while (dead_pid != 0); errno = errno_save; return; } int rabbits(void) { int sched_policy; int pid; pid = fork(); if (pid != 0) return 0; sched_policy = sched_getscheduler(0); if (sched_policy == -1) perror("sched_getscheduler"); /* Set the childs policy to SCHED_OTHER */ if (sched_policy != SCHED_OTHER) { struct sched_param sched; memset(&sched, 0, sizeof(sched)); sched.sched_priority = 0; if (sched_setscheduler(0, SCHED_OTHER, &sched) != 0) perror("sched_setscheduler"); } /* Set the priority of the process */ errno = 0; const int nice = getpriority(PRIO_PROCESS, 0); if (errno != 0) perror("getpriority"); if (nice < -10) if (setpriority(PRIO_PROCESS, 0, -10) != 0) perror("setpriority"); /* Launch helper program */ execvp(helper_program, helper_args); perror("execvp"); exit(EXIT_FAILURE); } int main(int argc, const char** argv, const char** envp) { struct sched_param sched; struct sigaction sas_child; int i; /* Set the round robin scheduler */ memset(&sched, 0, sizeof(sched)); sched.sched_priority = 26; if (sched_setscheduler(0, SCHED_RR, &sched) != 0) { perror("sched_setscheduler(SCHED_RR, 26)"); return 1; } /* Set a signal handler for children exiting */ memset(&sas_child, 0, sizeof(sas_child)); sas_child.sa_handler = child_signal_handler; if (sigaction(SIGCHLD, &sas_child, NULL) != 0) { perror("sigaction(SIGCHLD)"); return 1; } /* Create a large shared memory segment */ int seg1id = shmget(LARGE_SHARED_SEGMENT_KEY, LARGE_SHARED_SEGMENT_SIZE, IPC_CREAT|SHM_HUGETLB|0640); if (seg1id == -1) { perror("shmget(LARGE_SEGMENT)"); return 1; } /* Attach at the 16GB offset */ void* seg1adr = shmat(seg1id, LARGE_SHARED_SEGMENT_ADDR, 0); if (seg1adr == (void*)-1) { perror("shmat(LARGE_SEGMENT)"); return 1; } /* Initialise the start of the segment and mlock it */ memset(seg1adr, 0xFF, LARGE_SHARED_SEGMENT_SIZE/2); if (mlock(seg1adr, LARGE_SHARED_SEGMENT_SIZE) != 0) { perror("mlock(LARGE_SEGMENT)"); return 1; } /* Create a second smaller segment */ int seg2id = shmget(SMALL_SHARED_SEGMENT_KEY, SMALL_SHARED_SEGMENT_SIZE, IPC_CREAT|SHM_HUGETLB|0640); if (seg2id == -1) { perror("shmget(SMALL_SEGMENT)"); return 1; } /* Attach small segment */ void *seg2adr = shmat(seg2id, SMALL_SHARED_SEGMENT_ADDR, 0); if (seg2adr == (void*) -1) { perror("shmat(SMALL_SEGMENT)"); return 1; } /* Initialise all of small segment and mlock */ memset(seg2adr, 0xFF, (size_t) SMALL_SHARED_SEGMENT_SIZE); if (mlock(seg2adr, (size_t) SMALL_SHARED_SEGMENT_SIZE) != 0) { perror("mlock(SMALL_SEGMENT)"); return 1; } /* Create a number of approximately 516K buffers */ for (i = 0; i < NUM_SMALL_BUFFERS; i++) { void* mmtarg = mmap(NULL, 528384, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); if (mmtarg == (void*) -1) { perror("mmap"); return 1; } } /* Create one child per small buffer */ for (i = 0; i < NUM_SMALL_BUFFERS; i++) { rabbits(); usleep(500); } /* Wait until children shut up signalling */ printf("Waiting for children\n"); while (sleep(3) != 0); /* Detach */ if (shmdt(seg1adr) == -1) perror("shmdt(LARGE_SEGMENT)"); if (shmdt(seg2adr) == -1) perror("shmdt(SMALL_SEGMENT)"); if (shmctl(seg1id, IPC_RMID, NULL) == -1) perror("shmrm(LARGE_SEGMENT)"); if (shmctl(seg2id, IPC_RMID, NULL) == -1) perror("shmrm(SMALL_SEGMENT)"); printf("Done\n"); return 0; }