Created
December 20, 2016 15:43
-
-
Save sjenning/c9ee2a8cc2164ad42a0d5e0414b72f2e to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <assert.h> | |
#include <err.h> | |
#include <errno.h> | |
#include <fcntl.h> | |
#include <libgen.h> | |
#include <limits.h> | |
#include <stdio.h> | |
#include <string.h> | |
#include <unistd.h> | |
#include <stdlib.h> | |
#include <sys/eventfd.h> | |
#define USAGE_STR "Usage: cgroup_event_listener <path-to-control-file> <args>" | |
int main(int argc, char **argv) | |
{ | |
int efd = -1; | |
int cfd = -1; | |
int event_control = -1; | |
#define PATH_MAX 255 | |
#define LINE_MAX 255 | |
char event_control_path[PATH_MAX]; | |
char line[LINE_MAX]; | |
int ret; | |
int blksz_mbs = 20; | |
int allocated_mbs = 0; | |
#define MAXBLOCKS 300 | |
char *blocks[MAXBLOCKS]; | |
int index = 0; | |
char grow = 1; | |
int flags = 0; | |
if (argc != 3) | |
errx(1, "%s", USAGE_STR); | |
cfd = open(argv[1], O_RDONLY); | |
if (cfd == -1) | |
err(1, "Cannot open %s", argv[1]); | |
ret = snprintf(event_control_path, PATH_MAX, "%s/cgroup.event_control", | |
dirname(argv[1])); | |
if (ret >= PATH_MAX) | |
errx(1, "Path to cgroup.event_control is too long"); | |
event_control = open(event_control_path, O_WRONLY); | |
if (event_control == -1) | |
err(1, "Cannot open %s", event_control_path); | |
efd = eventfd(0, 0); | |
if (efd == -1) | |
err(1, "eventfd() failed"); | |
ret = snprintf(line, LINE_MAX, "%d %d %s", efd, cfd, argv[2]); | |
if (ret >= LINE_MAX) | |
errx(1, "Arguments string is too long"); | |
ret = write(event_control, line, strlen(line) + 1); | |
if (ret == -1) | |
err(1, "Cannot write to cgroup.event_control"); | |
flags = fcntl(efd, F_GETFL, 0); | |
ret = fcntl(efd, F_SETFL, flags | O_NONBLOCK); | |
if (ret == -1) | |
err(1, "Cannot set non-blocking read"); | |
#define PAGESIZE 4096 | |
while (1) { | |
uint64_t result; | |
char *mem; | |
if (grow) { | |
// allocate more memory to try to hit threshold | |
if (index >= MAXBLOCKS) | |
err(1, "maximum allowed sized reached without hitting threshold"); | |
mem = (char *)malloc(blksz_mbs<<20); | |
if (!mem) | |
err(1, "failed to allocate memory"); | |
blocks[index++] = mem; | |
allocated_mbs += blksz_mbs; | |
/* touch each page to force actual allocation */ | |
for (int i = 0; i < blksz_mbs<<20 ; i += PAGESIZE) { | |
memset(mem + i, 0, 1); | |
} | |
printf("allocated\n"); | |
} else { | |
// free memory to drop below threshold | |
if (index <= 0) | |
err(1, "no blocks left to free to get below threshold"); | |
free(blocks[--index]); | |
allocated_mbs -= blksz_mbs; | |
usleep(100000); | |
printf("freed\n"); | |
} | |
ret = read(efd, &result, sizeof(result)); | |
if (ret == -1) { | |
if (errno == EINTR) | |
continue; | |
if (errno == EAGAIN) { | |
printf("not at threshold yet. %d MB allocated.\n", allocated_mbs); | |
continue; | |
} | |
err(1, "Cannot read from eventfd"); | |
} | |
assert(ret == sizeof(result)); | |
printf("%s %s: crossed\n", argv[1], argv[2]); | |
grow = !grow; | |
} | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment