|
diff --git a/main.c b/main.c
|
| ... |
| 19 |
|
19 |
|
| 20 |
#include "file.h" |
20 |
#include "file.h" |
| 21 |
#include "list.h" |
21 |
#include "list.h" |
|
|
22 |
#include "tpool.h" |
| 22 |
|
23 |
|
| 23 |
#define DEBUG 1 |
24 |
#define DEBUG 0 |
| 24 |
|
25 |
|
| 25 |
typedef struct { |
26 |
typedef struct { |
| 26 |
const char* fname; |
27 |
const char *fname; |
| 27 |
const char* ftype; |
28 |
const char *ftype; |
| 28 |
const char* fparams; |
29 |
const char *fparams; |
| 29 |
size_t lineno; |
30 |
size_t lineno; |
| 30 |
} Function; |
31 |
} Function; |
| 31 |
|
32 |
|
| 32 |
const char* extract_value(TSNode captured_node, const char* source_code) { |
33 |
const char *extract_value(TSNode captured_node, const char *source_code) { |
| 33 |
size_t start = ts_node_start_byte(captured_node); |
34 |
size_t start = ts_node_start_byte(captured_node); |
| 34 |
size_t end = ts_node_end_byte(captured_node); |
35 |
size_t end = ts_node_end_byte(captured_node); |
| 35 |
size_t length = end - start; |
36 |
size_t length = end - start; |
| 36 |
char* buffer = malloc(length + 1); // +1 for the null terminator |
37 |
char *buffer = malloc(length + 1); // +1 for the null terminator |
| 37 |
|
38 |
|
| 38 |
if (buffer != NULL) { |
39 |
if (buffer != NULL) { |
| 39 |
snprintf(buffer, length + 1, "%.*s", (int)length, &source_code[start]); |
40 |
snprintf(buffer, length + 1, "%.*s", (int)length, &source_code[start]); |
| 40 |
return buffer; |
41 |
return buffer; |
| 41 |
} |
42 |
} else { |
|
|
43 |
perror("malloc"); |
|
|
44 |
exit(EXIT_FAILURE); |
|
|
45 |
} |
| 42 |
|
46 |
|
| 43 |
return NULL; |
47 |
return NULL; |
| 44 |
} |
48 |
} |
| 45 |
|
49 |
|
| 46 |
char* remove_newlines(const char* str) { |
50 |
char *remove_newlines(const char *str) { |
| 47 |
size_t length = strlen(str); |
51 |
if (str == NULL) |
| 48 |
char* result = (char*)malloc(length + 1); // +1 for the null terminator |
52 |
return NULL; |
| 49 |
if (result == NULL) { |
53 |
size_t length = strlen(str); |
| 50 |
fprintf(stderr, "Memory allocation failed\n"); |
54 |
char *result = (char *)malloc(length + 1); // +1 for the null terminator |
| 51 |
exit(1); |
55 |
if (result == NULL) { |
| 52 |
} |
56 |
fprintf(stderr, "Memory allocation failed\n"); |
|
|
57 |
exit(1); |
|
|
58 |
} |
| 53 |
|
59 |
|
| 54 |
size_t j = 0; |
60 |
size_t j = 0; |
| 55 |
for (size_t i = 0; i < length; i++) { |
61 |
for (size_t i = 0; i < length; i++) { |
| 56 |
if (str[i] != '\n') { |
62 |
if (str[i] != '\n') { |
| 57 |
result[j++] = str[i]; |
63 |
result[j++] = str[i]; |
| 58 |
} |
64 |
} |
| 59 |
} |
65 |
} |
| 60 |
|
66 |
|
| 61 |
result[j] = '\0'; |
67 |
result[j] = '\0'; |
| 62 |
return result; |
68 |
return result; |
| 63 |
} |
69 |
} |
| 64 |
|
70 |
|
| 65 |
struct ThreadArgs { |
71 |
struct ThreadArgs { |
| 66 |
const char* file_path; |
72 |
const char *file_path; |
| 67 |
const char* source_code; |
73 |
const char *source_code; |
| 68 |
TSLanguage* language; |
74 |
TSLanguage *language; |
| 69 |
const char* cfname; |
75 |
const char *cfname; |
| 70 |
}; |
76 |
}; |
| 71 |
|
77 |
|
| 72 |
// void parse_source_file(const char *file_path, const char *source_code, |
78 |
// void parse_source_file(const char *file_path, const char *source_code, |
| 73 |
// TSLanguage *language, const char *cfname) { |
79 |
// TSLanguage *language, const char *cfname) { |
| 74 |
void* parse_source_file(void* arg) { |
80 |
void parse_source_file(void *arg) { |
| 75 |
struct ThreadArgs* args = (struct ThreadArgs*)arg; |
81 |
struct ThreadArgs *args = (struct ThreadArgs *)arg; |
| 76 |
|
82 |
|
| 77 |
const char* file_path = args->file_path; |
83 |
const char *file_path = args->file_path; |
| 78 |
const char* source_code = args->source_code; |
84 |
const char *source_code = args->source_code; |
| 79 |
TSLanguage* language = args->language; |
85 |
TSLanguage *language = args->language; |
| 80 |
const char* cfname = args->cfname; |
86 |
const char *cfname = args->cfname; |
| 81 |
|
87 |
|
| 82 |
TSParser* parser = ts_parser_new(); |
88 |
TSParser *parser = ts_parser_new(); |
| 83 |
ts_parser_set_language(parser, language); |
89 |
ts_parser_set_language(parser, language); |
| 84 |
|
90 |
|
| 85 |
TSTree* tree = |
91 |
TSTree *tree = |
| 86 |
ts_parser_parse_string(parser, NULL, source_code, strlen(source_code)); |
92 |
ts_parser_parse_string(parser, NULL, source_code, strlen(source_code)); |
| 87 |
TSNode root_node = ts_tree_root_node(tree); |
93 |
TSNode root_node = ts_tree_root_node(tree); |
| 88 |
|
94 |
|
| 89 |
const char* query_string = |
95 |
const char *query_string = |
| 90 |
"(function_definition type: (primitive_type) @ftype declarator: " |
96 |
"(function_definition type: (_) @ftype declarator: (function_declarator declarator: (identifier) @fname parameters: (parameter_list) @fparams))" |
| 91 |
"(function_declarator declarator: (identifier) @fname parameters: " |
97 |
"(function_definition type: (_) @ftype declarator: (pointer_declarator declarator: (function_declarator declarator: (identifier) @fname parameters: (parameter_list) @fparams)))" |
| 92 |
"(parameter_list) @fparams))"; |
98 |
"(declaration type: (_) @ftype declarator: (function_declarator declarator: (identifier) @fname parameters: (parameter_list) @fparams))" |
|
|
99 |
"(declaration type: (_) @ftype declarator: (pointer_declarator declarator: (function_declarator declarator: (identifier) @fname parameters: (parameter_list) @fparams)))"; |
| 93 |
|
100 |
|
| 94 |
uint32_t error_offset; |
101 |
uint32_t error_offset; |
| 95 |
TSQueryError error_type; |
102 |
TSQueryError error_type; |
| 96 |
TSQuery* query = ts_query_new(language, query_string, strlen(query_string), |
103 |
TSQuery *query = ts_query_new(language, query_string, strlen(query_string), &error_offset, &error_type); |
| 97 |
&error_offset, &error_type); |
|
|
| 98 |
|
104 |
|
| 99 |
TSQueryCursor* query_cursor = ts_query_cursor_new(); |
105 |
TSQueryCursor *query_cursor = ts_query_cursor_new(); |
| 100 |
ts_query_cursor_exec(query_cursor, query, root_node); |
106 |
ts_query_cursor_exec(query_cursor, query, root_node); |
| 101 |
|
107 |
|
| 102 |
if (query != NULL) { |
108 |
if (query != NULL) { |
| 103 |
TSQueryMatch match; |
109 |
TSQueryMatch match; |
| 104 |
while (ts_query_cursor_next_match(query_cursor, &match)) { |
110 |
while (ts_query_cursor_next_match(query_cursor, &match)) { |
| 105 |
Function fn = {0}; |
111 |
Function fn = {0}; |
| 106 |
|
112 |
|
| 107 |
for (unsigned i = 0; i < match.capture_count; i++) { |
113 |
for (unsigned i = 0; i < match.capture_count; i++) { |
| 108 |
TSQueryCapture capture = match.captures[i]; |
114 |
TSQueryCapture capture = match.captures[i]; |
| 109 |
TSNode captured_node = capture.node; |
115 |
TSNode captured_node = capture.node; |
| 110 |
|
116 |
|
| 111 |
uint32_t capture_name_length; |
117 |
uint32_t capture_name_length; |
| 112 |
const char* capture_name = ts_query_capture_name_for_id( |
118 |
const char *capture_name = ts_query_capture_name_for_id( |
| 113 |
query, capture.index, &capture_name_length); |
119 |
query, capture.index, &capture_name_length); |
| 114 |
|
120 |
|
| 115 |
if (strcmp(capture_name, "fname") == 0) { |
121 |
if (strcmp(capture_name, "fname") == 0) { |
| 116 |
fn.fname = extract_value(captured_node, source_code); |
122 |
fn.fname = extract_value(captured_node, source_code); |
| 117 |
|
123 |
|
| 118 |
TSPoint start_point = ts_node_start_point(captured_node); |
124 |
TSPoint start_point = ts_node_start_point(captured_node); |
| 119 |
fn.lineno = start_point.row; |
125 |
fn.lineno = start_point.row; |
| 120 |
} |
126 |
} |
| 121 |
|
127 |
|
| 122 |
if (strcmp(capture_name, "ftype") == 0) { |
128 |
if (strcmp(capture_name, "ftype") == 0) { |
| 123 |
fn.ftype = extract_value(captured_node, source_code); |
129 |
fn.ftype = extract_value(captured_node, source_code); |
| 124 |
} |
130 |
} |
| 125 |
|
131 |
|
| 126 |
if (strcmp(capture_name, "fparams") == 0) { |
132 |
if (strcmp(capture_name, "fparams") == 0) { |
| 127 |
fn.fparams = extract_value(captured_node, source_code); |
133 |
fn.fparams = extract_value(captured_node, source_code); |
| 128 |
} |
134 |
} |
| 129 |
} |
135 |
} |
| 130 |
|
136 |
|
| 131 |
// Substring matching. |
137 |
// Substring matching. |
| 132 |
// FIXME: Add Levenshtein distance. |
138 |
// FIXME: Add Levenshtein distance. |
| 133 |
char* result = strstr(fn.fname, cfname); |
139 |
if (fn.fname != NULL) { |
| 134 |
if (result != NULL) { |
140 |
char *result = strstr(fn.fname, cfname); |
| 135 |
char* fparams_formatted = remove_newlines(fn.fparams); |
141 |
if (result != NULL) { |
| 136 |
printf("%s:%zu:\t%s %s %s\n", file_path, fn.lineno, fn.ftype, fn.fname, |
142 |
char *fparams_formatted = remove_newlines(fn.fparams); |
| 137 |
fparams_formatted); |
143 |
printf("%s:%zu:\t%s %s %s\n", file_path, fn.lineno, fn.ftype, fn.fname, fparams_formatted); |
| 138 |
} |
144 |
free(fparams_formatted); |
| 139 |
} |
145 |
} |
| 140 |
} else { |
146 |
} |
| 141 |
if (DEBUG) { |
|
|
| 142 |
printf("Query creation failed at offset %u with error type %d\n", |
|
|
| 143 |
error_offset, error_type); |
|
|
| 144 |
} |
|
|
| 145 |
} |
|
|
| 146 |
|
147 |
|
| 147 |
ts_query_cursor_delete(query_cursor); |
148 |
// Free captured values |
| 148 |
ts_query_delete(query); |
149 |
free((void *)fn.fname); |
| 149 |
ts_tree_delete(tree); |
150 |
free((void *)fn.ftype); |
| 150 |
ts_parser_delete(parser); |
151 |
free((void *)fn.fparams); |
|
|
152 |
} |
|
|
153 |
} else { |
|
|
154 |
if (DEBUG) { |
|
|
155 |
printf("Query creation failed at offset %u with error type %d\n", error_offset, error_type); |
|
|
156 |
} |
|
|
157 |
} |
|
|
158 |
|
|
|
159 |
ts_query_cursor_delete(query_cursor); |
|
|
160 |
ts_query_delete(query); |
|
|
161 |
ts_tree_delete(tree); |
|
|
162 |
ts_parser_delete(parser); |
| 151 |
|
163 |
|
| 152 |
return NULL; |
164 |
// Cleanup thread arguments |
|
|
165 |
free((void *)source_code); |
|
|
166 |
free(args); |
| 153 |
} |
167 |
} |
| 154 |
|
168 |
|
| 155 |
const char* get_file_extension(const char* file_path) { |
169 |
const char *get_file_extension(const char *file_path) { |
| 156 |
const char* extension = strrchr(file_path, '.'); |
170 |
const char *extension = strrchr(file_path, '.'); |
| 157 |
if (extension != NULL) { |
171 |
if (extension != NULL) { |
| 158 |
return extension + 1; |
172 |
return extension + 1; |
| 159 |
} |
173 |
} |
| 160 |
return NULL; |
174 |
return NULL; |
| 161 |
} |
175 |
} |
| 162 |
|
176 |
|
| 163 |
int main(int argc, char* argv[]) { |
177 |
int main(int argc, char *argv[]) { |
| 164 |
if (argc < 3) { |
178 |
if (argc < 3) { |
| 165 |
printf("Usage: %s <search term> <directory>\n", argv[0]); |
179 |
printf("Usage: %s <search term> <directory>\n", argv[0]); |
| 166 |
return 1; |
180 |
return 1; |
| 167 |
} |
181 |
} |
| 168 |
|
182 |
|
| 169 |
char* cfname = argv[1]; |
183 |
const char *cfname = argv[1]; |
| 170 |
char* directory = argv[2]; |
184 |
char *directory = argv[2]; |
| 171 |
|
185 |
|
| 172 |
TSLanguage* tree_sitter_c(void); |
186 |
TSLanguage *tree_sitter_c(void); |
| 173 |
TSLanguage* tree_sitter_python(void); |
187 |
TSLanguage *tree_sitter_python(void); |
| 174 |
|
188 |
|
| 175 |
Node* head = NULL; |
189 |
Node *head = NULL; |
| 176 |
list_files_recursively(directory, &head); |
190 |
list_files_recursively(directory, &head); |
| 177 |
int list_size = size_of_file_list(head); |
191 |
int list_size = size_of_file_list(head); |
| 178 |
/* pthread_t threads[list_size]; */ |
|
|
| 179 |
|
192 |
|
| 180 |
if (DEBUG) { |
193 |
if (DEBUG) { |
| 181 |
printf("Scanning %d files\n", list_size); |
194 |
printf("Scanning %d files\n", list_size); |
| 182 |
} |
195 |
} |
| 183 |
|
196 |
|
| 184 |
Node* current = head; |
197 |
ThreadPool *pool = tp_create(8); |
| 185 |
// int thread_index = 0; |
198 |
if (!pool) { |
| 186 |
while (current != NULL) { |
199 |
perror("Failed to create thread pool"); |
| 187 |
const char* file_path = current->file_path; |
200 |
return 1; |
| 188 |
const char* extension = get_file_extension(file_path); |
201 |
} |
| 189 |
struct FileContent source_file = read_entire_file(file_path); |
|
|
| 190 |
|
202 |
|
| 191 |
if (source_file.content != NULL) { |
203 |
Node *current = head; |
| 192 |
if (extension != NULL) { |
204 |
while (current != NULL) { |
| 193 |
if (strcmp(extension, "c") == 0 || strcmp(extension, "h") == 0) { |
205 |
const char *file_path = current->file_path; |
| 194 |
/* parse_source_file(file_path, source_file.content, tree_sitter_c(), |
206 |
const char *extension = get_file_extension(file_path); |
| 195 |
* cfname); */ |
|
|
| 196 |
|
207 |
|
| 197 |
struct ThreadArgs thread_args; |
208 |
if (extension != NULL && (strcmp(extension, "c") == 0 || strcmp(extension, "h") == 0)) { |
| 198 |
thread_args.file_path = file_path; |
209 |
struct FileContent source_file = read_entire_file(file_path); |
| 199 |
thread_args.source_code = source_file.content; |
210 |
if (source_file.content != NULL) { |
| 200 |
thread_args.language = tree_sitter_c(); |
211 |
struct ThreadArgs *thread_args = malloc(sizeof(struct ThreadArgs)); |
| 201 |
thread_args.cfname = cfname; |
212 |
if (!thread_args) { |
|
|
213 |
perror("Failed to allocate thread args"); |
|
|
214 |
free((void *)source_file.content); |
|
|
215 |
continue; |
|
|
216 |
} |
| 202 |
|
217 |
|
| 203 |
parse_source_file(&thread_args); |
218 |
thread_args->file_path = file_path; |
|
|
219 |
thread_args->source_code = source_file.content; |
|
|
220 |
thread_args->language = tree_sitter_c(); |
|
|
221 |
thread_args->cfname = cfname; |
| 204 |
|
222 |
|
| 205 |
/* printf("> creating thread #%d\n", thread_index); */ |
223 |
tp_add_job(pool, (thread_func_t)parse_source_file, thread_args); |
| 206 |
/* if (pthread_create(&threads[thread_index], NULL, parse_source_file, |
224 |
} else { |
| 207 |
* &thread_args) != 0) { */ |
225 |
if (DEBUG) { |
| 208 |
/* fprintf(stderr, "Error creating thread %d\n", thread_index); */ |
226 |
fprintf(stderr, "Failed to read file: %s\n", file_path); |
| 209 |
/* return 1; */ |
227 |
} |
| 210 |
/* } */ |
228 |
} |
| 211 |
} |
229 |
} |
| 212 |
} |
|
|
| 213 |
free((void*)source_file.content); |
|
|
| 214 |
} else { |
|
|
| 215 |
if (DEBUG) { |
|
|
| 216 |
fprintf(stderr, "Failed to read file.\n"); |
|
|
| 217 |
} |
|
|
| 218 |
} |
|
|
| 219 |
current = current->next; |
|
|
| 220 |
// thread_index++; |
|
|
| 221 |
} |
|
|
| 222 |
|
230 |
|
| 223 |
// Collecting threads. |
231 |
current = current->next; |
| 224 |
/* for (int i = 0; i < list_size; i++) { */ |
232 |
} |
| 225 |
/* printf("> collecting thread #%d\n", thread_index); */ |
|
|
| 226 |
/* if (pthread_join(threads[i], NULL) != 0) { */ |
|
|
| 227 |
/* fprintf(stderr, "Error joining thread %d\n", i); */ |
|
|
| 228 |
/* return 1; */ |
|
|
| 229 |
/* } */ |
|
|
| 230 |
/* } */ |
|
|
| 231 |
|
233 |
|
| 232 |
free_file_list(head); |
234 |
tp_wait(pool); |
| 233 |
return 0; |
235 |
tp_destroy(pool); |
|
|
236 |
free_file_list(head); |
|
|
237 |
return 0; |
| 234 |
} |
238 |
} |
|
diff --git a/tpool.c b/tpool.c
|
|
|
1 |
#include "tpool.h" |
|
|
2 |
#include <stdio.h> |
|
|
3 |
#include <stdlib.h> |
|
|
4 |
|
|
|
5 |
typedef struct ThreadPoolJobNode { |
|
|
6 |
ThreadPoolJob job; |
|
|
7 |
struct ThreadPoolJobNode *next; |
|
|
8 |
} ThreadPoolJobNode; |
|
|
9 |
|
|
|
10 |
struct ThreadPool { |
|
|
11 |
pthread_mutex_t lock; |
|
|
12 |
pthread_cond_t notify; |
|
|
13 |
pthread_cond_t working_cond; |
|
|
14 |
|
|
|
15 |
pthread_t *threads; |
|
|
16 |
int num_threads; |
|
|
17 |
|
|
|
18 |
ThreadPoolJobNode *queue_head; |
|
|
19 |
ThreadPoolJobNode *queue_tail; |
|
|
20 |
|
|
|
21 |
int active_jobs; // Jobs currently running |
|
|
22 |
int queued_jobs; // Jobs waiting in queue |
|
|
23 |
bool stop; |
|
|
24 |
}; |
|
|
25 |
|
|
|
26 |
static void *tp_worker(void *arg) { |
|
|
27 |
ThreadPool *pool = (ThreadPool *)arg; |
|
|
28 |
|
|
|
29 |
while (1) { |
|
|
30 |
pthread_mutex_lock(&pool->lock); |
|
|
31 |
|
|
|
32 |
while (pool->queue_head == NULL && !pool->stop) { |
|
|
33 |
pthread_cond_wait(&pool->notify, &pool->lock); |
|
|
34 |
} |
|
|
35 |
|
|
|
36 |
if (pool->stop && pool->queue_head == NULL) { |
|
|
37 |
pthread_mutex_unlock(&pool->lock); |
|
|
38 |
break; |
|
|
39 |
} |
|
|
40 |
|
|
|
41 |
ThreadPoolJobNode *node = pool->queue_head; |
|
|
42 |
pool->queue_head = node->next; |
|
|
43 |
if (pool->queue_head == NULL) { |
|
|
44 |
pool->queue_tail = NULL; |
|
|
45 |
} |
|
|
46 |
|
|
|
47 |
pool->queued_jobs--; |
|
|
48 |
pool->active_jobs++; |
|
|
49 |
|
|
|
50 |
pthread_mutex_unlock(&pool->lock); |
|
|
51 |
|
|
|
52 |
// Execute job |
|
|
53 |
if (node->job.function) { |
|
|
54 |
node->job.function(node->job.arg); |
|
|
55 |
} |
|
|
56 |
free(node); |
|
|
57 |
|
|
|
58 |
pthread_mutex_lock(&pool->lock); |
|
|
59 |
pool->active_jobs--; |
|
|
60 |
if (pool->active_jobs == 0 && pool->queue_head == NULL) { |
|
|
61 |
pthread_cond_signal(&pool->working_cond); |
|
|
62 |
} |
|
|
63 |
pthread_mutex_unlock(&pool->lock); |
|
|
64 |
} |
|
|
65 |
|
|
|
66 |
return NULL; |
|
|
67 |
} |
|
|
68 |
|
|
|
69 |
ThreadPool *tp_create(int num_threads) { |
|
|
70 |
ThreadPool *pool = (ThreadPool *)malloc(sizeof(ThreadPool)); |
|
|
71 |
if (pool == NULL) |
|
|
72 |
return NULL; |
|
|
73 |
|
|
|
74 |
pool->num_threads = num_threads; |
|
|
75 |
pool->queue_head = NULL; |
|
|
76 |
pool->queue_tail = NULL; |
|
|
77 |
pool->active_jobs = 0; |
|
|
78 |
pool->queued_jobs = 0; |
|
|
79 |
pool->stop = false; |
|
|
80 |
|
|
|
81 |
pthread_mutex_init(&pool->lock, NULL); |
|
|
82 |
pthread_cond_init(&pool->notify, NULL); |
|
|
83 |
pthread_cond_init(&pool->working_cond, NULL); |
|
|
84 |
|
|
|
85 |
pool->threads = (pthread_t *)malloc(sizeof(pthread_t) * num_threads); |
|
|
86 |
for (int i = 0; i < num_threads; i++) { |
|
|
87 |
pthread_create(&pool->threads[i], NULL, tp_worker, pool); |
|
|
88 |
} |
|
|
89 |
|
|
|
90 |
return pool; |
|
|
91 |
} |
|
|
92 |
|
|
|
93 |
void tp_add_job(ThreadPool *pool, thread_func_t function, void *arg) { |
|
|
94 |
ThreadPoolJobNode *node = (ThreadPoolJobNode *)malloc(sizeof(ThreadPoolJobNode)); |
|
|
95 |
if (node == NULL) { |
|
|
96 |
perror("malloc"); |
|
|
97 |
exit(EXIT_FAILURE); |
|
|
98 |
} |
|
|
99 |
node->job.function = function; |
|
|
100 |
node->job.arg = arg; |
|
|
101 |
node->next = NULL; |
|
|
102 |
|
|
|
103 |
pthread_mutex_lock(&pool->lock); |
|
|
104 |
|
|
|
105 |
if (pool->queue_tail) { |
|
|
106 |
pool->queue_tail->next = node; |
|
|
107 |
} else { |
|
|
108 |
pool->queue_head = node; |
|
|
109 |
} |
|
|
110 |
pool->queue_tail = node; |
|
|
111 |
|
|
|
112 |
pool->queued_jobs++; |
|
|
113 |
pthread_cond_signal(&pool->notify); |
|
|
114 |
|
|
|
115 |
pthread_mutex_unlock(&pool->lock); |
|
|
116 |
} |
|
|
117 |
|
|
|
118 |
void tp_wait(ThreadPool *pool) { |
|
|
119 |
pthread_mutex_lock(&pool->lock); |
|
|
120 |
while (pool->active_jobs > 0 || pool->queue_head != NULL) { |
|
|
121 |
pthread_cond_wait(&pool->working_cond, &pool->lock); |
|
|
122 |
} |
|
|
123 |
pthread_mutex_unlock(&pool->lock); |
|
|
124 |
} |
|
|
125 |
|
|
|
126 |
void tp_destroy(ThreadPool *pool) { |
|
|
127 |
pthread_mutex_lock(&pool->lock); |
|
|
128 |
pool->stop = true; |
|
|
129 |
pthread_cond_broadcast(&pool->notify); |
|
|
130 |
pthread_mutex_unlock(&pool->lock); |
|
|
131 |
|
|
|
132 |
for (int i = 0; i < pool->num_threads; i++) { |
|
|
133 |
pthread_join(pool->threads[i], NULL); |
|
|
134 |
} |
|
|
135 |
|
|
|
136 |
free(pool->threads); |
|
|
137 |
pthread_mutex_destroy(&pool->lock); |
|
|
138 |
pthread_cond_destroy(&pool->notify); |
|
|
139 |
pthread_cond_destroy(&pool->working_cond); |
|
|
140 |
free(pool); |
|
|
141 |
} |