-
Notifications
You must be signed in to change notification settings - Fork 1
/
parallel.c
218 lines (196 loc) · 5.68 KB
/
parallel.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
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <stdlib.h>
#include "command-internals.h"
#include "command.h"
#include "alloc.h"
#include "parallel.h"
#include "file_tree.h"
#include "llist.h"
void
get_files (command_t cmd, file_tree *head)
{
char **word;
switch (cmd->type)
{
case AND_COMMAND:
case SEQUENCE_COMMAND:
case OR_COMMAND:
case PIPE_COMMAND:
get_files (cmd->u.command[0], head);
get_files (cmd->u.command[1], head);
break;
case SIMPLE_COMMAND:
if (cmd->input)
insert_file_tree (head, cmd->input, 0);
if (cmd->output)
insert_file_tree (head, cmd->output, 1);
word = cmd->u.word;
while (*word)
{
insert_file_tree (head, *word, 0);
word++;
}
break;
case SUBSHELL_COMMAND:
if (cmd->input)
insert_file_tree (head, cmd->input, 0);
if (cmd->output)
insert_file_tree (head, cmd->output, 1);
get_files (cmd->u.subshell_command, head);
break;
}
}
bool
files_dependent (file_tree files1, file_tree files2)
{
if (!files1 || !files2)
return false; // Can't search null values
if (files_dependent (files1->left, files2))
return true;
else if (files_dependent (files1->right, files2))
return true;
else
{
file_tree search = find_file (files2, files1->filename);
// Return false if we didn't find anything
if (search == 0)
return false;
else // Otherwise we check if one of them is being written to
return (files1->written_to || files2->written_to);
}
}
bool
dependent_commands_arrs (command_array cmd_arr1, command_array cmd_arr2)
{
return files_dependent (cmd_arr1.files, cmd_arr2.files);
}
// Finds ranking of cmd in cmd_arr. Assumes cmd_arr is non-zero sized
size_t
find_ranking (command_array *cmd_info, command_array **cmd_arr, size_t arr_size)
{
int position;
position = arr_size - 1;
// Find the first dependent command
while (0 <= position &&
!dependent_commands_arrs (*cmd_info, (*cmd_arr)[position]))
{
position--;
}
// Found the first command it is dependent on
// Special case for -1
if (position == -1)
{
// Not dependent on anything
return 0;
}
// The ranking is one more than the first dependent command
return (*cmd_arr)[position].ranking + 1;
}
// Changes cmd_arr to have the cmd_info in its proper place (assumes
// cmd_info has already been completely filled)
void
place_command_by_ranking (command_array *cmd_info, command_array **cmd_arr,
size_t arr_size)
{
int i;
// Shift everything to match ranking
// This is definitely not the most efficient sort. However, if we don't place
// commands into their proper position, we could get less optimal scheduling
i = (int)(arr_size);
while (0 < i && cmd_info->ranking < (*cmd_arr)[i-1].ranking)
{
(*cmd_arr)[i] = (*cmd_arr)[i-1];
i--;
}
// initialize the values of the command
(*cmd_arr)[i] = *cmd_info;
#ifdef DEBUG
int j;
for (j = 0; j != (int)arr_size+1; j++) {
printf ("%d -- cmd: %x, files: %x, rank: %d\n",
j,
(unsigned int)(*cmd_arr)[j].command_tree,
(unsigned int)(*cmd_arr)[j].files,
(*cmd_arr)[j].ranking);
print_command ((*cmd_arr)[j].command_tree);
}
printf("FINAL ENDED\n\n\n\n");
#endif
}
// Adds a command to the list of processes, ranked by parallelizability
void
add_command_t (command_t cmd, command_array **cmd_arr,
size_t *arr_size, size_t *arr_capacity)
{
command_array cmd_info;
cmd_info.command_tree = cmd;
// Make the File Tree
file_tree head = 0;
get_files (cmd_info.command_tree, &head);
cmd_info.files = head;
// Check Size of the array, allocate more memory if needed
if (*arr_capacity <= *arr_size)
{
size_t new_capacity = (*arr_capacity) * (sizeof (command_array));
*cmd_arr = checked_grow_alloc (*cmd_arr, &new_capacity);
*arr_capacity = new_capacity / (sizeof (command_array));
}
// Initialize new command_array element's command tree
if (*arr_size != 0)
{
cmd_info.ranking = find_ranking (&cmd_info, cmd_arr, *arr_size);
place_command_by_ranking (&cmd_info, cmd_arr, *arr_size);
}
else // The first command is always independent
{
cmd_info.ranking = 0;
(*cmd_arr)[*arr_size] = cmd_info;
}
// Change Array Size
(*arr_size)++;
}
int
excute_parallel (command_array *cmd_arr, size_t arr_size)
{
int status;
size_t i;
node_t n;
node_t pid_list;
// List of pids to wait for
pid_list = initialize_llist ();
i = 0;
// Go through all the processes
while (i < arr_size)
{
int pid;
size_t current = cmd_arr[i].ranking;
while (i < arr_size && cmd_arr[i].ranking == current)
{
pid = fork();
// Spawn the child process to execute the command
if (pid == 0) // child process
{
execute_command (cmd_arr[i].command_tree);
exit (command_status (cmd_arr[i].command_tree));
}
insert_node (pid_list, pid);
i++;
}
// Wait for all the processes of this ranking to finish
for (n = pid_list->next; n != pid_list; n = n->next)
waitpid(n->val, &status, 0);
// Processes finished waiting for
while (pid_list != pid_list->next)
remove_last_element (pid_list);
}
// Return the status of the last process waited on
return status;
}
// Frees the command arrays commands and file tree
void free_command_array_dependents (command_array cmd_arr)
{
free_command (cmd_arr.command_tree);
free_file_tree (cmd_arr.files);
}