-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathtls.c
345 lines (288 loc) · 8.75 KB
/
tls.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
/*
* Thread-project
*
* Autor: David Cabeza <13-10191@usb.ve>
* Autor: Fabiola Martínez <13-10838@usb.ve>
*
* Descripción: Este archivo contiene varias definiciones de las funciones
* utilizadas a lo largo del thread-list: análisis de argumentos, inicialización
* de estructuras, manejo de hilos, exploración de directorios, asignación y
* escritura de salida
*
* Universidad Simón Bolívar
* Caracas, Venezuela
* Marzo, 2017
*
*/
#include "tls.h"
/* help: procedimiento que se encarga de mostrar en pantalla un mensaje de ayu-
* da sobre sintaxis, parametros de entrada y salida.
*/
void help(void){
execlp("pager", "pager", "help");
}
/* usage: se ejecuta cuando se invoca el programa con un comando inválido.
*/
void usage(void){
printf("uso: tls [-h] | [-n i] [-d directorio] [salida]\n");
printf("ejecute tls -h para mayor información\n");
exit(0);
}
/* init_inputarg: procedimiento que se encarga de inicializar los valores intro-
* ducidos por el usuario.
*/
void init_inputargs(Inargs *in){
in->concurrency = 1;
getcwd(in->directory, PATH_MAX);
strcpy(in->out, "stdout");
}
/* parseArgs: procedimiento que se encarga de verificar la instruccion que desea
* ejecutar el usuario.
*/
void parseArgs(Inargs *in, int argc, char *argv[]){
int ch;
bool h, nd;
h = false;
nd = false;
while( (ch = getopt(argc, argv, "hn:d:")) != -1)
switch(ch){
case 'h':
h = true;
break;
case 'n':
if (!isdigit(optarg[0])) usage();
in->concurrency = atoi(optarg);
nd = true;
break;
case 'd':
strcpy(in->directory, optarg);
nd = true;
break;
case '?':
usage();
default:
usage();
}
if(h && nd) usage();
else if (h) help();
if(optind < argc) strcpy(in->out, argv[optind]);
}
/* init_threastruct: procedimiento que se encarga de inicializar los valores co-
* rrespondientes a los los atributos de un hilo.
* Parametros de entrada:
* - t: apuntador a estructura threadstruct.
* - thnum: numeros de hilos creados.
* - dirlist: apuntador a la lista de directorios pendientes.
* - infolis: apuntador a la lista que almacena la informacion obtenida por los
* hilos.
* - idlelist: apuntador a la lista de hilos que no tienen trabajo asignado.
*/
void init_threadstruct(Threadstruct *t, int thnum, List *dirlist,
List* infolist, List *idlelist){
t->id = 0;
t->thnum = thnum;
t->has_dirallocated = 0;
t->dirlist = dirlist;
t->infolist = infolist;
t->idlelist = idlelist;
}
/* init_information: procedimiento que se encarga de inicializar los valores en
* en los que se almacena la informacion obtenida por el hilo.
* Parametros de entrada:
* - i: apuntador a la estructura information que contendra la informacion ob-
* tenida por el nodo.
* - id: identificador del hilo.
* - dir: directorio explorado por el hilo.
* - fcount: cantidad de archivos encontrados por el hilos.
* - bcount: cantidad de bytes.
*/
void init_information(Information *i, long id, char *dir, int fcount,
int bcount){
i->id = id;
strcpy(i->path, dir);
i->fcount = fcount;
i->bcount = bcount;
}
/* onwork: procedimiento que verifica si hay hilos trabajando.
* Parametros de entrada:
* - thnum: numeros de hilos creados.
* - idlelist: apuntador a la lista de hilos que no tienen trabajo asignado.
*/
int onwork(int thnum, List* idlelist){
return (thnum != idlelist->size);
}
/* threadmgmt: procedimiento que sera ejecutada por los hijos, verifica si
* un hilo tiene un directorio asignado para que este inicie a explorar el
* directorio que se le fue asignado.
* Parametros de entrada:
* - structure:
*/
void *threadmgmt(void *structure){
Threadstruct *t;
Node *n;
int i;
t = (Threadstruct *) structure;
t->id = pthread_self();
// Se verifica si hay directorios pendientes por asignar o hay hilos ociosos.
while(!empty(t->dirlist) || onwork(t->thnum, t->idlelist)){
// Se verifica si el hilo tiene directorio asignado
if(t->has_dirallocated){
// Hilo hijo explora directorio
explore(t);
// Hilo termino de explorar, se ajustan sus valores como el de un
// hilo ocioso.
t->has_dirallocated = 0;
n = (Node *) malloc(sizeof(Node));
init_node(n, t);
pthread_mutex_lock(&idlemutex);
add(t->idlelist, n);
pthread_mutex_unlock(&idlemutex);
}
}
pthread_exit(NULL);
}
/* createThreads: procedimiento que se encarga de crear los hilos trabajadores.
* Parametros de entrada:
* - thnum: numeros de hilos creados.
* - dirlist: apuntador a la lista de directorios pendientes.
* - infolis: apuntador a la lista que almacena la informacion obtenida por los
* hilos.
* - idlelist: apuntador a la lista de hilos que no tienen trabajo asignado.
*/
void createThreads(Threadstruct *master, pthread_t *threads){
int rc, i;
Threadstruct *t;
Node *n;
for (i = 0; i < master->thnum; i++) {
// Se crean hilos hijos.
t = (Threadstruct *) malloc(sizeof(Threadstruct));
// Se inicializan sus valores.
init_threadstruct(t, master->thnum, master->dirlist, master->infolist,
master->idlelist);
n = (Node *) (malloc(sizeof(Node)));
init_node(n, t);
// Se anaden hilos ociosos a la idlelist
add(master->idlelist, n);
rc = pthread_create(&threads[i], NULL, threadmgmt, t);
if (rc){
printf("Error al crear hilo. Código de error:%d\n", rc);
exit(-1);
}
}
}
/* explore: procedimiento que se encarga de explorar un directorio.
* Parametros de entrada:
* - t: apuntador a la estructura del hilo.
*/
void explore(Threadstruct *t){
DIR *dp;
struct dirent *ep;
struct stat statbuffer;
char subdir[PATH_MAX];
Node *n;
Directory *d;
Information *i;
int filescount, bytescount;
filescount = 0;
bytescount = 0;
dp = opendir(t->directory);
if(!dp){
perror("No fue posible abrir el directorio\n");
return;
}
while((ep = readdir(dp)) != NULL){
// Ignore hiden directories
if(ep->d_name[0] != '.'){
strcpy(subdir, t->directory);
strcat(subdir, "/");
strcat(subdir, ep->d_name);
if(lstat(subdir, &statbuffer) == -1){
perror("No se pudo obtener la información del archivo\n");
return;
}
if(S_ISDIR(statbuffer.st_mode)){
n = (Node *) malloc(sizeof(Node));
d = (Directory *) malloc(sizeof(Directory));
strcpy(d->dir, subdir);
init_node(n, d);
pthread_mutex_unlock(&dirmutex);
add(t->dirlist, n);
pthread_mutex_unlock(&dirmutex);
continue;
}
else{
filescount++;
bytescount += statbuffer.st_size;
continue;
}
}
}
closedir(dp);
n = (Node *) malloc(sizeof(Node));
i = (Information *) malloc(sizeof(Information));
init_information(i, t->id, t->directory, filescount, bytescount);
init_node(n, i);
pthread_mutex_lock(&infomutex);
add(t->infolist, n);
pthread_mutex_unlock(&infomutex);
}
/* allocateDir: procedimiento que se encarga de asignarle un directorio a un hi-
* lo ociosio, sin trabajo.
* Parametros de entrada:
* - t: apuntador a la estructura del hilo.
*/
void allocateDir(Threadstruct *master){
Node *c, *d;
Threadstruct *t;
// Se verifica si hay directorios pendientes por asignar o hay hilos ociosos.
while(!empty(master->dirlist) || onwork(master->thnum, master->idlelist)){
if(master->idlelist->size != 0 && master->dirlist->size != 0){
// Región crítica: Obtenemos hilo ociosio, sin trabajo.
pthread_mutex_lock(&idlemutex);
c = get(master->idlelist);
t = (Threadstruct *) c->content;
pthread_mutex_unlock(&idlemutex);
// Región crítica: Obtenemos directorio pendiente por explorar.
pthread_mutex_lock(&dirmutex);
d = get(master->dirlist);
// Asignamos directorio al hilo ocioso
t->has_dirallocated = 1;
strcpy(t->directory, d->content);
pthread_mutex_unlock(&dirmutex);
}
}
}
/* writeInformation: procedimiento que se encarga mostrar la informacion reci-
* bida del hilo padre por sus hijos y mostrarla por defecto en la linea de co-
* mando o si el usuario lo desea en un archivo de salida.
* Parametros de entrada:
* - out: nombre del archivo de salida.
*/
void writeInformation(Threadstruct *master, char *out){
FILE *f;
Node *first, *next;
Information *info;
bool file_specified;
file_specified = false;
if(strcmp(out,"stdout")){
f = fopen(out, "w");
file_specified = true;
}
if(master->infolist->size){
first = master->infolist->first;
info = (Information *) first->content;
if (file_specified) fprintf(f, "%ld %s %d %lu\n", info->id, info->path,
info->fcount, info->bcount);
else fprintf(stdout, "%ld %s %d %lu\n", info->id, info->path,
info->fcount, info->bcount);
next = first->next;
while(next){
info = (Information *) next->content;
if (file_specified) fprintf(f, "%ld %s %d %d\n", info->id, info->path,
info->fcount, info->bcount);
else fprintf(stdout, "%ld %s %d %d\n", info->id, info->path,
info->fcount, info->bcount);
next = next->next;
}
}
}