Skip to content

Instantly share code, notes, and snippets.

@pmj
Forked from weissi/file-size.c
Last active December 31, 2015 19:18
Show Gist options
  • Select an option

  • Save pmj/8032259 to your computer and use it in GitHub Desktop.

Select an option

Save pmj/8032259 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;
}
unsigned num_write_events = 0, num_ext_events = 0;
memset(changelist, 0, sizeof(changelist));
EV_SET(&changelist[0], fd, EVFILT_VNODE, EV_ADD | EV_ENABLE | EV_CLEAR, NOTE_DELETE | NOTE_RENAME | NOTE_EXTEND | NOTE_WRITE, 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: %u write %u extend events\n", num_write_events, num_ext_events);
goto out;
}
/*if (num_ext_events >= 10)
{
printf("%uth extend event\n", num_ext_events);
}*/
if (num_write_events >= 10)
{
printf("%uth write event\n", num_write_events);
}
}
{
/* 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) %u write %u extend events\n", new_sz, num_write_events, num_ext_events);
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";
++num_ext_events;
}
if ( changelist[0].filter == EVFILT_VNODE &&
changelist[0].fflags & NOTE_WRITE) {
type = "WRITE";
++num_write_events;
}
/*
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 write_fd = dup(xfd);//open(FILENAME, O_WRONLY);
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
{
size_t remain = size_per_write;
ssize_t written;
do
{
written = write(write_fd, buf, remain);
if (written <= 0)
{
fprintf(stderr, "Write failed: written = %ld, errno = %d (%s)\n", written, errno, strerror(errno));
exit(1);
}
remain -= written;
} while (remain > 0);
}
#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()
{
for (unsigned i = 0; i < 100000; ++i)
{
FILE* f = tmpfile();
int fd = fileno(f);//open(FILENAME, O_CREAT | O_TRUNC | O_RDWR, 0777);
assert(fd >= 0);
pid_t p = fork();
if (p == 0)
{
do_writes(fd);
return 0;
}
else if (p < 0)
{
perror("fork failed\n");
return 1;
}
go_on(fd);
fclose(f);
wait(NULL);
if (i % 200 == 199)
printf("%d attempts done\n", i + 1);
}
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment