Skip to content

Instantly share code, notes, and snippets.

@weissi
Last active December 30, 2015 21:49
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save weissi/7890467 to your computer and use it in GitHub Desktop.
Save weissi/7890467 to your computer and use it in GitHub Desktop.
#include <assert.h>
#include <dispatch/dispatch.h>
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/event.h>
#include <sys/event.h>
#include <sys/select.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/types.h>
#include <sys/types.h>
#include <unistd.h>
#define FILENAME "/tmp/.some-tmp-file"
#define MAX_FILE_SIZE 10*1000*1000
int get_fd_size(int fd)
{
off_t eof_pos = lseek(fd, 0, SEEK_END);
return eof_pos;
}
void go_on(int fd)
{
int ret = -1;
int kq = kqueue();
struct kevent changelist[1];
if (kq < 0) {
/* errno set by kqueue */
ret = -1;
goto out;
}
memset(changelist, 0, sizeof(changelist));
EV_SET(&changelist[0], fd, EVFILT_VNODE, EV_ADD | EV_ENABLE | EV_CLEAR, NOTE_DELETE | NOTE_RENAME | NOTE_EXTEND, 0, 0);
if (kevent(kq, changelist, 1, NULL, 0, NULL) < 0) {
/* errno set by kevent */
ret = -1;
goto out;
}
while (1) {
{
/* Step 1: Check the size */
off_t new_sz = get_fd_size(fd);
printf("new size: %lld\n", new_sz);
if (new_sz >= MAX_FILE_SIZE) {
printf("Ok, success\n");
exit(0);
}
}
{
/* Step 2: Wait for growth */
struct timespec timeout = { .tv_sec = 1, .tv_nsec = 0 };
int suc_kev = kevent(kq, NULL, 0, changelist, 1, &timeout);
if (0 == suc_kev) {
/* That's a timeout */
off_t new_sz = get_fd_size(fd);
printf("Timeout (%lld)\n", new_sz);
errno = ETIMEDOUT;
ret = -1;
goto out;
} else if (suc_kev > 0) {
char *type = "?";
if ( changelist[0].filter == EVFILT_VNODE &&
changelist[0].fflags & NOTE_EXTEND) {
type = "EXTEND";
}
if ( changelist[0].filter == EVFILT_VNODE &&
changelist[0].fflags & NOTE_WRITE) {
type = "WRITE";
}
printf("kevent %s #%p (%p | %p)\n", type, changelist[0].ident, changelist[0].data, changelist[0].udata);
if (changelist[0].filter == EVFILT_VNODE) {
if (changelist[0].fflags & NOTE_RENAME || changelist[0].fflags & NOTE_DELETE) {
/* file was deleted, renamed, ... */
printf("Renamed\n");
errno = ENOENT;
ret = -1;
goto out;
}
}
} else {
/* errno set by kevent */
printf("Error: %d\n", errno);
ret = -1;
goto out;
}
}
}
out: {
int errno_save = errno;
if (kq >= 0) {
close(kq);
}
errno = errno_save;
return;
}
}
void do_writes(int xfd)
{
int fd = open(FILENAME, O_WRONLY);
const int write_fd = dup(fd);
const off_t size_per_write = MAX_FILE_SIZE / 10;
const off_t desired_size = MAX_FILE_SIZE;
char *buf = malloc(size_per_write);
memset(buf, 'A', size_per_write);
for (int i=0; i<desired_size / size_per_write; i++) {
#ifndef USE_FTRUNCATE
{
ssize_t suc_write = write(write_fd, buf, size_per_write);
assert(suc_write == size_per_write);
}
#else
ftruncate(write_fd, (1+i) * size_per_write);
#endif
printf("wrote\n");
fsync(write_fd);
usleep(100000);
}
free(buf);
{
struct stat stat_buf = {0};
fstat(write_fd, &stat_buf);
printf("writing thread finished: desired: %lld, actual: %lld\n", desired_size, stat_buf.st_size);
}
/*
close(write_fd);
close(fd);
*/
}
int main()
{
int fd = open(FILENAME, O_CREAT | O_TRUNC | O_RDWR, 0777);
assert(fd >= 0);
dispatch_async_f(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), (void *)fd, do_writes);
go_on(fd);
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment