/**
Zadanie:
program ma 1 parameter:
./a.out -n<N> <directory>
- pouzivejte getopt()
Ukol:
V adresari vzit regularni soubory
- nad kazdym souborem spustit vlakno - (predate mu nejak jmeno souboru)
- vlakno zjisti velikost souboru a updatuje citac velikosti reg.souboru toho adresare.(f)
cislo N - v jednu chvili muze bezet max. N vlaken, jakmile jedno skonci, spustim dalsi.
- spravna synch. citac, max. N vlaken
- osetrovat chyby (nad etc)
13:45- 16:15
- vystup - cislo + njekay debugging vhodny
*/
// for fdopendir
#ifndef __USE_GNU
# define __USE_GNU
#endif
#ifndef _ATFILE_SOURCE
# define _ATFILE_SOURCE
#endif
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <error.h>
#include <err.h>
#include <errno.h>
#include <pthread.h> // threads
#include <dirent.h> // readdir...
#include <sys/types.h>
#include <sys/stat.h> // stat, fstatat, ...
#include <fcntl.h>
void usage(char* argv0)
{
fprintf(stderr, "usage: %s -n<N> <directory>\n", argv0);
exit(1);
}
int ACT_THRS = 0;
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
off_t ALLSIZE = 0;
void *
adderthr(void *val)
{
struct stat* fileinfo = (struct stat*) val;
// zamkneme
pthread_mutex_lock(&mutex);
printf("AKTUALNY POCET VLAKIEN: %d sucet: %d = %d + %d\n", ACT_THRS, ALLSIZE, ALLSIZE, fileinfo->st_size);
// pricitame velkost suboru
ALLSIZE += fileinfo->st_size;
--ACT_THRS;
// vlakno vykonalo pricitanie, signalizacia pre vypustenie dalsieho vlakna
pthread_cond_signal(&cond);
// odomkneme
pthread_mutex_unlock(&mutex);
// poll(NULL, 0, 95);
return val;
}
void secti(char* dirname, int N)
{
DIR *d;
int dirfd;
struct dirent *de;
struct stat* fileinfo;
void * thr_retval;
int i;
int threadnr = 0;
int threadsize = 10;
// cisla vsetkych threadov pre joinovanie
pthread_t* threads;
if ((threads = malloc(threadsize * sizeof(pthread_t))) == NULL)
errx(1, "chyba naalokovania tabulky threadov");
if ((dirfd = open(dirname, O_RDONLY)) < 0)
errx(1, "Chyba otvorenia zlozky dirdf - %s", dirname);
// perror(dirname);
if ((d = fdopendir(dirfd)) == NULL)
errx(1, "Chyba otvorenia zlozky fdopendir - %s", dirname);
// Rozlisenie medzi koncom zlozky a chybou
errno = 0;
while ((de = readdir(d))) {
// ked je to regularny subor
if ((fileinfo = malloc(sizeof(struct stat))) == NULL)
perror("malloc");
// nenasleduje symlinky
if (fstatat(dirfd, de->d_name, fileinfo, AT_SYMLINK_NOFOLLOW) == -1)
perror("fstatat");
if (de->d_type == DT_REG) {
// if (S_ISREG(fileinfo->st_mode)) {
pthread_mutex_lock(&mutex);
printf("spracovanie suboru %s\n", de->d_name);
// uspi a caka kym skoncia vlakna
while (ACT_THRS == N) {
pthread_cond_wait(&cond, &mutex);
}
if (threadnr == threadsize) {
// realloc
threadsize = threadsize * 2;
if ((threads = realloc(threads, threadsize * sizeof(pthread_t))) == NULL)
perror("realloc");
}
++ACT_THRS;
pthread_create(&threads[threadnr++], NULL, adderthr, (void *) fileinfo);
// zobudi vlakna
// if (ACT_THRS < N)
// pthread_cond_signal(&cond);
pthread_mutex_unlock(&mutex);
} else {
printf("neregularny subor: %s\n", de->d_name);
free(fileinfo);
}
}
// join all threads
for (i = 0; i != threadnr; ++i) {
pthread_join(threads[i], &thr_retval);
// uvolnenie zdrojov
fileinfo = (struct stat*) thr_retval;
free(fileinfo);
}
free(threads);
if (errno != 0)
warn("%s", dirname);
printf("HOTOVO: vysledok: %ld", (long int)ALLSIZE);
// directory closed by close
// closedir(d);
if (close(dirfd) == -1)
perror("close");
}
int main(int argc, char* argv[])
{
int N = 10; // default number of threads
char *dirname;
int opt;
char *argv0 = argv[0];
// opterr = 0;
if (argc < 2)
usage(argv0);
printf("first param (command): %s\n", argv[1]);
argv++;
argc--;
while ((opt = getopt(argc, argv, "n:")) != -1)
{
switch (opt)
{
case 'n':
printf("option -c set to '%s'\n", optarg);
N = atoi(optarg);
break;
case '?':
usage(argv0);
break;
}
}
printf("option arguments done\n");
/* optind is the 1st non-option argument */
argv = argv + optind;
if (argv[0] != NULL)
{
printf("dirname:");
dirname = argv[0];
printf(" %s\n", dirname);
} else {
printf("no filenames entered\n");
usage(argv0);
}
secti(dirname, N);
return (EXIT_SUCCESS);
}