-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmultithreaded.c
More file actions
213 lines (181 loc) · 5.89 KB
/
Copy pathmultithreaded.c
File metadata and controls
213 lines (181 loc) · 5.89 KB
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
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <assert.h>
#include <stdint.h>
#include <string.h>
#include <sys/types.h>
#include <dirent.h>
// Initialize locks
pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t increment_done_lock = PTHREAD_MUTEX_INITIALIZER;
// Globals
char *global_search_string;
int open_dirs = 1;
struct queue *taskqueue;
struct node {
char path[250];
struct node *next;
};
struct queue {
struct node *front;
struct node *rear;
pthread_mutex_t queue_lock;
};
// Task queue function signatures
struct queue* initqueue();
void enqueue(struct queue*, char*);
void dequeue(struct queue*);
int isEmpty(struct queue*);
void printqueue(struct queue*);
//
void *search(void *id) {
uintptr_t worker_ID = (uintptr_t) id;
char dir_path[250];
while (open_dirs > 0) {
int empty = 0;
pthread_mutex_lock(&lock);
empty = isEmpty(taskqueue);
pthread_mutex_unlock(&lock);
if(!empty){
// Take a new job
pthread_mutex_lock(&lock); // Only one thread can take a single job at a time
if(isEmpty(taskqueue)) {
pthread_mutex_unlock(&lock);
continue; // Continue loop if task queue has become empty.
}
strcpy(dir_path, taskqueue->front->path);
dequeue(taskqueue);
pthread_mutex_unlock(&lock);
char abs_path[250] = {0};
realpath(dir_path, abs_path);
printf("[%ld] DIR %s\n", worker_ID, abs_path);
DIR *dir = opendir(dir_path);
if (dir == NULL) continue;
struct dirent *content;
while ((content = readdir(dir)) != NULL) {
if (!strcmp(content->d_name, ".") || !strcmp(content->d_name, "..")) continue;
int type = content->d_type;
if (type == DT_DIR) { // Child is a directory
pthread_mutex_lock(&lock); // Only one thread can modify task queue at a time
char new_path[250] = {0};
strcat(new_path, dir_path);
strcat(new_path, "/");
strcat(new_path, content->d_name);
enqueue(taskqueue, new_path);
realpath(new_path, abs_path);
printf("[%ld] ENQUEUE %s\n", worker_ID, abs_path);
pthread_mutex_lock(&increment_done_lock);
open_dirs++;
pthread_mutex_unlock(&increment_done_lock);
pthread_mutex_unlock(&lock);
}
else if (type == DT_REG) { // Child is a file
char grep_command[600];
char file_path[250] = {0};
strcat(file_path, dir_path);
strcat(file_path, "/");
strcat(file_path, content->d_name);
sprintf(grep_command, "grep \"%s\" \"%s\" 1> /dev/null", global_search_string, file_path);
int grep_retval = system(grep_command);
realpath(file_path, abs_path);
if (grep_retval == 0)
printf("[%ld] PRESENT %s\n", worker_ID, abs_path);
else
printf("[%ld] ABSENT %s\n", worker_ID, abs_path);
}
}
closedir(dir);
pthread_mutex_lock(&increment_done_lock);
open_dirs--;
pthread_mutex_unlock(&increment_done_lock);
}
else {
continue;
}
}
return NULL;
}
int main(int argc, char *argv[]) {
assert(argc == 4);
int n_workers = atoi(argv[1]);
char *rootpath = argv[2];
char *search_string = argv[3];
global_search_string = search_string;
// Main thread enqueues rootpath
taskqueue = initqueue();
enqueue(taskqueue, rootpath);
// Thread creation
pthread_t workers[n_workers];
for (uintptr_t i = 0; i < n_workers; i++) {
pthread_create(&workers[i], NULL, search, (void *)i);
}
for (uintptr_t i = 0; i < n_workers; i++) {
pthread_join(workers[i], NULL);
}
free(taskqueue);
return 0;
}
// TASK QUEUE METHODS
struct queue* initqueue() {
struct queue *tasks = (struct queue*)malloc(sizeof(struct queue));
tasks->front = NULL;
tasks->rear = NULL;
pthread_mutex_init(&tasks->queue_lock, NULL);
return tasks;
}
void enqueue(struct queue *tasks, char *path) {
struct node *newnode = (struct node*)malloc(sizeof(struct node));
assert(newnode != NULL);
strcpy(newnode->path, path);
newnode->next = NULL;
pthread_mutex_lock(&tasks->queue_lock);
if (tasks->front == NULL) {
tasks->front = newnode;
tasks->rear = newnode;
}
else {
tasks->rear->next = newnode;
tasks->rear = newnode;
}
pthread_mutex_unlock(&tasks->queue_lock);
}
void dequeue(struct queue *tasks) {
pthread_mutex_lock(&tasks->queue_lock);
struct node *temp = tasks->front;
if (temp == NULL) {
pthread_mutex_unlock(&tasks->queue_lock);
return;
}
else {
tasks->front = temp->next;
pthread_mutex_unlock(&tasks->queue_lock);
free(temp);
return;
}
}
int isEmpty(struct queue *tasks) {
pthread_mutex_lock(&tasks->queue_lock);
if (tasks->front == NULL) {
pthread_mutex_unlock(&tasks->queue_lock);
return 1;
}
else {
pthread_mutex_unlock(&tasks->queue_lock);
return 0;
}
}
void printqueue(struct queue *tasks) {
struct node *current = tasks->front;
if (current == NULL) {
printf("No tasks queued.\n");
return;
}
printf("\nQUEUE: ");
while(current != NULL) {
printf("%s--", current->path);
current = current->next;
}
printf("\n");
free(current);
}