#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <signal.h>
#include <assert.h>
#include <fcntl.h>
#include <string.h>
#include <unistd.h>
#include <wait.h>
#include <sys/shm.h>
/*
* Creates dirty data and issue sync at the end.
* Child creates enough dirty data, issues fsync. Parent synchronizes with
* child and soon as fsync is issued, dispatches KILL.
* If KILL was unsuccessful, a flag in shared memory is set.
* Parent verifies this flag to ensure test result.
*/
union semun {
int val;
struct semid_ds *buf;
unsigned short *array;
struct seminfo *__buf;
};
int main(int argc, char ** argv)
{
int shm_id;
char* shm_addr, *data_array;
struct shmid_ds shm_desc;
union semun data;
struct sembuf op;
int sem_id;
int status, pid, fd, len, loop;
int count = 0, ret = 1, data_size;
int *post_sync;
if (argc != 3) {
printf("Usage : synctest <len> <loop> \n");
exit(1);
}
len = atoi(argv[1]);
loop = atoi(argv[2]);
data_size = len * 1024 * 1024;
/* allocate a shared memory segment with size of 10 bytes. */
shm_id = shmget(IPC_PRIVATE, 10, IPC_CREAT | IPC_EXCL | 0600);
if (shm_id == -1) {
perror("main : shmget \n");
exit(1);
}
/* attach the shared memory segment to our process's address space. */
shm_addr = shmat(shm_id, NULL, 0);
if (!shm_addr) { /* operation failed. */
perror("main : shmat \n");
goto early_out;
}
post_sync = (int*) shm_addr;
*post_sync = 0;
fd = open("testfile", O_RDWR|O_CREAT|O_APPEND|O_NONBLOCK);
if (!fd) {
perror("main : Failed to create data file \n");
goto out;
}
data_array = (char *)malloc(data_size * sizeof(char));
if (!data_array) {
perror("main : Not enough memory \n");
goto out;
}
op.sem_num = 0;
sem_id = semget(IPC_PRIVATE, 1, IPC_CREAT);
if (sem_id < 0){
perror("main : semget \n");
goto out;
}
data.val = 0;
semctl(sem_id, 0, SETVAL, data);
pid = fork();
if (pid < 0)
{
perror("main : fork failed \n");
goto out;
}
if (!pid)
{
/* child process */
while (count++ < loop) {
write(fd, data_array, data_size * (sizeof(char)));
}
printf("CHLD : start sync \n");
/* increment sema */
op.sem_op = 1;
semop(sem_id, &op, 1);
/* wait for parent */
op.sem_op = 0;
semop(sem_id, &op, 1);
fsync(fd);
*post_sync = 1;
return 0 ;
} else {
/* parent process */
/* waiting for child to increment sema */
op.sem_op = -1;
semop(sem_id, &op, 1);
/* some sleep so fsync gets started before we kill*/
sleep(1);
ret = kill(pid, SIGKILL);
if (ret) {
perror("main : kill failed \n");
goto out;
}
printf("PAR : waiting\n");
wait(&status);
}
ret = *post_sync;
if (!ret)
printf("PASS : sync interrupted \n");
else
printf("FAIL : sync not interrupted \n");
out:
/* detach the shared memory segment from our process's address space. */
if (shmdt(shm_addr) == -1) {
perror("main : shmdt");
}
close(fd);
system("rm -f testfile \n");
early_out:
/* de-allocate the shared memory segment. */
if (shmctl(shm_id, IPC_RMID, &shm_desc) == -1) {
perror("main : shmctl");
}
return ret;
}