#include <errno.h>
#include <fcntl.h>
#include <mk/defs.h>
#include <mksh/dosys.h>
#include <mksh/macro.h>
#include <mksh/misc.h>
#include <sys/signal.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/utsname.h>
#include <sys/wait.h>
#include <unistd.h>
#include <netdb.h>
#include <libintl.h>
#define MAXRULES 100
const int local_host_mask = 0x20;
static Boolean just_did_subtree = false;
static char local_host[MAXNAMELEN] = "";
static char user_name[MAXNAMELEN] = "";
static int pmake_max_jobs = 0;
static pid_t process_running = -1;
static Running *running_tail = &running_list;
static Name subtree_conflict;
static Name subtree_conflict2;
static void delete_running_struct(Running rp);
static Boolean dependency_conflict(Name target);
static Doname distribute_process(char **commands, Property line);
static void doname_subtree(Name target, Boolean do_get, Boolean implicit);
static void dump_out_file(char *filename, Boolean err);
static void finish_doname(Running rp);
static void maybe_reread_make_state(void);
static void process_next(void);
static void reset_conditionals(int cnt, Name *targets, Property *locals);
static pid_t run_rule_commands(char *host, char **commands);
static Property *set_conditionals(int cnt, Name *targets);
static void store_conditionals(Running rp);
Doname
execute_parallel(Property line, Boolean waitflg, Boolean local)
{
int argcnt;
int cmd_options = 0;
char *commands[MAXRULES + 5];
char *cp;
Name dmake_name;
Name dmake_value;
int ignore;
Name make_machines_name;
char **p;
Property prop;
Doname result = build_ok;
Cmd_line rule;
Boolean silent_flag;
Name target = line->body.line.target;
Boolean wrote_state_file = false;
if ((pmake_max_jobs == 0) &&
(dmake_mode_type == parallel_mode)) {
if (local_host[0] == '\0') {
(void) gethostname(local_host, MAXNAMELEN);
}
MBSTOWCS(wcs_buffer, "DMAKE_MAX_JOBS");
dmake_name = GETNAME(wcs_buffer, FIND_LENGTH);
if (((prop = get_prop(dmake_name->prop, macro_prop)) != NULL) &&
((dmake_value = prop->body.macro.value) != NULL)) {
pmake_max_jobs = atoi(dmake_value->string_mb);
if (pmake_max_jobs <= 0) {
warning(gettext("DMAKE_MAX_JOBS cannot be less than or equal to zero."));
warning(gettext("setting DMAKE_MAX_JOBS to %d."), PMAKE_DEF_MAX_JOBS);
pmake_max_jobs = PMAKE_DEF_MAX_JOBS;
}
} else {
MBSTOWCS(wcs_buffer, "PMAKE_MACHINESFILE");
dmake_name = GETNAME(wcs_buffer, FIND_LENGTH);
if (((prop = get_prop(dmake_name->prop, macro_prop)) != NULL) &&
((dmake_value = prop->body.macro.value) != NULL)) {
make_machines_name = dmake_value;
} else {
make_machines_name = NULL;
}
if ((pmake_max_jobs = read_make_machines(make_machines_name)) <= 0) {
pmake_max_jobs = PMAKE_DEF_MAX_JOBS;
}
}
}
if ((dmake_mode_type == serial_mode) ||
((dmake_mode_type == parallel_mode) && (waitflg))) {
return (execute_serial(line));
}
{
p = commands;
}
argcnt = 0;
for (rule = line->body.line.command_used;
rule != NULL;
rule = rule->next) {
if (posix && (touch || quest) && !rule->always_exec) {
continue;
}
if (vpath_defined) {
rule->command_line =
vpath_translation(rule->command_line);
}
silent_flag = false;
ignore = 0;
if (rule->command_line->hash.length > 0) {
if (++argcnt == MAXRULES) {
return build_serial;
}
{
if (rule->silent && !silent) {
silent_flag = true;
}
if (rule->ignore_error) {
ignore++;
}
if (silent_flag || ignore) {
*p = getmem((silent_flag ? 1 : 0) +
ignore +
(strlen(rule->
command_line->
string_mb)) +
1);
cp = *p++;
if (silent_flag) {
*cp++ = (int) at_char;
}
if (ignore) {
*cp++ = (int) hyphen_char;
}
(void) strcpy(cp, rule->command_line->string_mb);
} else {
*p++ = rule->command_line->string_mb;
}
}
}
}
if ((argcnt == 0) ||
(report_dependencies_level > 0)) {
return build_ok;
}
{
*p = NULL;
Doname res = distribute_process(commands, line);
if (res == build_running) {
parallel_process_cnt++;
}
for (int i = 0; commands[i] != NULL; i++) {
if ((commands[i][0] == (int) at_char) ||
(commands[i][0] == (int) hyphen_char)) {
retmem_mb(commands[i]);
}
}
return res;
}
}
#include <unistd.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <semaphore.h>
#include <sys/loadavg.h>
static int
adjust_pmake_max_jobs (int pmake_max_jobs)
{
static int ncpu = 0;
double loadavg[3];
int adjustment;
int adjusted_max_jobs;
if (ncpu <= 0) {
if ((ncpu = sysconf(_SC_NPROCESSORS_ONLN)) <= 0) {
ncpu = 1;
}
}
if (getloadavg(loadavg, 3) != 3) return(pmake_max_jobs);
adjustment = ((int)loadavg[LOADAVG_1MIN]);
if (adjustment < 2) return(pmake_max_jobs);
if (ncpu > 1) {
adjustment = adjustment / ncpu;
}
adjusted_max_jobs = pmake_max_jobs - adjustment;
if (adjusted_max_jobs < 1) adjusted_max_jobs = 1;
return(adjusted_max_jobs);
}
static char m2_file[MAXPATHLEN];
static int m2_shm_id = -1;
static sem_t* m2_shm_sem = 0;
static int
m2_init() {
char *var;
key_t key;
if ((var = getenv("__DMAKE_M2_FILE__")) == 0) {
sprintf(m2_file, "%s/dmake.m2.%d.XXXXXX", tmpdir, getpid());
int fd = mkstemp(m2_file);
if (fd < 0) {
return -1;
} else {
close(fd);
}
} else {
strcpy(m2_file, var);
}
if ((key = ftok(m2_file, 38)) == (key_t) -1) {
return -1;
}
if ((m2_shm_id = shmget(key, sizeof(*m2_shm_sem), 0666 | (var ? 0 : IPC_CREAT|IPC_EXCL))) == -1) {
return -1;
}
if ((m2_shm_sem = (sem_t*) shmat(m2_shm_id, 0, 0666)) == (sem_t*)-1) {
return -1;
}
if (var == 0) {
if (sem_init(m2_shm_sem, 1, pmake_max_jobs)) {
return -1;
}
if ((var = (char*) malloc(MAXPATHLEN)) == 0) {
return -1;
}
sprintf(var, "__DMAKE_M2_FILE__=%s", m2_file);
if (putenv(var)) {
return -1;
}
}
return 0;
}
static void
m2_fini() {
if (m2_shm_id >= 0) {
struct shmid_ds stat;
if (shmctl(m2_shm_id, IPC_STAT, &stat) == 0) {
if (stat.shm_nattch <= 1) {
if (m2_shm_sem != 0) {
(void) sem_destroy(m2_shm_sem);
}
(void) shmctl(m2_shm_id, IPC_RMID, &stat);
(void) unlink(m2_file);
} else {
if (m2_shm_sem != 0) {
(void) shmdt((char*) m2_shm_sem);
}
}
}
m2_shm_id = -1;
m2_shm_sem = 0;
}
}
static int
m2_acquire_job() {
if ((m2_shm_id >= 0) && (m2_shm_sem != 0)) {
if (sem_trywait(m2_shm_sem) == 0) {
return 1;
}
if (errno == EAGAIN) {
return 0;
}
}
return -1;
}
static int
m2_release_job() {
if ((m2_shm_id >= 0) && (m2_shm_sem != 0)) {
if (sem_post(m2_shm_sem) == 0) {
return 0;
}
}
return -1;
}
static enum {
ADJUST_UNKNOWN,
ADJUST_M1,
ADJUST_M2,
ADJUST_NONE
} job_adjust_mode = ADJUST_UNKNOWN;
void
job_adjust_fini() {
if (job_adjust_mode == ADJUST_M2) {
m2_fini();
}
}
static void
job_adjust_error() {
if (job_adjust_mode != ADJUST_NONE) {
job_adjust_fini();
warning(gettext("Encountered max jobs auto adjustment error - disabling auto adjustment."));
putenv(strdup("DMAKE_ADJUST_MAX_JOBS=NO"));
job_adjust_mode = ADJUST_NONE;
}
}
static void
job_adjust_init() {
if (job_adjust_mode == ADJUST_UNKNOWN) {
job_adjust_mode = ADJUST_M1;
if (char *var = getenv("DMAKE_ADJUST_MAX_JOBS")) {
if (strcasecmp(var, "NO") == 0) {
job_adjust_mode = ADJUST_NONE;
} else if (strcasecmp(var, "M2") == 0) {
job_adjust_mode = ADJUST_M2;
}
}
if (job_adjust_mode == ADJUST_M2) {
if (m2_init()) {
job_adjust_error();
}
}
}
}
static Doname
distribute_process(char **commands, Property line)
{
static unsigned file_number = 0;
wchar_t string[MAXPATHLEN];
char mbstring[MAXPATHLEN];
int filed;
int res;
int tmp_index;
char *tmp_index_str_ptr;
if (job_adjust_mode == ADJUST_UNKNOWN) {
job_adjust_init();
}
switch (job_adjust_mode) {
case ADJUST_M1:
while (parallel_process_cnt >= adjust_pmake_max_jobs (pmake_max_jobs)) {
await_parallel(false);
finish_children(true);
}
break;
case ADJUST_M2:
if ((res = m2_acquire_job()) == 0) {
if (parallel_process_cnt > 0) {
await_parallel(false);
finish_children(true);
if ((res = m2_acquire_job()) == 0) {
return build_serial;
}
} else {
return build_serial;
}
}
if (res < 0) {
job_adjust_error();
while (parallel_process_cnt >= pmake_max_jobs) {
await_parallel(false);
finish_children(true);
}
}
break;
default:
while (parallel_process_cnt >= pmake_max_jobs) {
await_parallel(false);
finish_children(true);
}
}
setvar_envvar();
if (!silent && output_mode != txt2_mode) {
(void) fprintf(stdout,
gettext("%s --> %d %s\n"),
local_host,
parallel_process_cnt + 1,
(parallel_process_cnt == 0) ? gettext("job") : gettext("jobs"));
tmp_index = 0;
while (commands[tmp_index] != NULL) {
if ((commands[tmp_index][0] != (int) at_char) &&
(commands[tmp_index][1] != (int) at_char)) {
tmp_index_str_ptr = commands[tmp_index];
if (*tmp_index_str_ptr == (int) hyphen_char) {
tmp_index_str_ptr++;
}
(void) fprintf(stdout, "%s\n", tmp_index_str_ptr);
}
tmp_index++;
}
(void) fflush(stdout);
}
(void) sprintf(mbstring,
"%s/dmake.stdout.%d.%d.XXXXXX",
tmpdir,
getpid(),
file_number++);
mktemp(mbstring);
stdout_file = strdup(mbstring);
stderr_file = NULL;
if (!out_err_same) {
(void) sprintf(mbstring,
"%s/dmake.stderr.%d.%d.XXXXXX",
tmpdir,
getpid(),
file_number++);
mktemp(mbstring);
stderr_file = strdup(mbstring);
}
process_running = run_rule_commands(local_host, commands);
return build_running;
}
Doname
doname_parallel(Name target, Boolean do_get, Boolean implicit)
{
Doname result;
result = doname_check(target, do_get, implicit, false);
if (result == build_ok || result == build_failed) {
return result;
}
finish_running();
return (Doname) target->state;
}
static void
doname_subtree(Name target, Boolean do_get, Boolean implicit)
{
Running save_running_list;
Running *save_running_tail;
save_running_list = running_list;
save_running_tail = running_tail;
running_list = NULL;
running_tail = &running_list;
target->state = build_subtree;
target->checking_subtree = true;
while(doname_check(target, do_get, implicit, false) == build_running) {
target->checking_subtree = false;
finish_running();
target->state = build_subtree;
}
target->checking_subtree = false;
running_list = save_running_list;
running_tail = save_running_tail;
}
void
finish_running(void)
{
while (running_list != NULL) {
{
await_parallel(false);
finish_children(true);
}
if (running_list != NULL) {
process_next();
}
}
}
static void
process_next(void)
{
Running rp;
Running *rp_prev;
Property line;
Chain target_group;
Dependency dep;
Boolean quiescent = true;
Running *subtree_target;
Boolean saved_commands_done;
Property *conditionals;
subtree_target = NULL;
subtree_conflict = NULL;
subtree_conflict2 = NULL;
start_loop_1:
for (rp_prev = &running_list, rp = running_list;
rp != NULL && parallel_process_cnt == 0;
rp = rp->next) {
if (rp->state == build_serial) {
*rp_prev = rp->next;
if (rp->next == NULL) {
running_tail = rp_prev;
}
recursion_level = rp->recursion_level;
rp->target->state = build_pending;
(void) doname_check(rp->target,
rp->do_get,
rp->implicit,
false);
quiescent = false;
delete_running_struct(rp);
goto start_loop_1;
} else {
rp_prev = &rp->next;
}
}
start_loop_2:
for (rp_prev = &running_list, rp = running_list;
rp != NULL;
rp = rp->next) {
if (!(rp->state == build_pending ||
rp->state == build_subtree)) {
quiescent = false;
rp_prev = &rp->next;
} else if (rp->state == build_pending) {
line = get_prop(rp->target->prop, line_prop);
for (dep = line->body.line.dependencies;
dep != NULL;
dep = dep->next) {
if (dep->name->state == build_running ||
dep->name->state == build_pending ||
dep->name->state == build_serial) {
break;
}
}
if (dep == NULL) {
for (target_group = line->body.line.target_group;
target_group != NULL;
target_group = target_group->next) {
if (is_running(target_group->name)) {
break;
}
}
if (target_group == NULL) {
*rp_prev = rp->next;
if (rp->next == NULL) {
running_tail = rp_prev;
}
recursion_level = rp->recursion_level;
rp->target->state = rp->redo ?
build_dont_know : build_pending;
saved_commands_done = commands_done;
conditionals =
set_conditionals
(rp->conditional_cnt,
rp->conditional_targets);
rp->target->dont_activate_cond_values = true;
if ((doname_check(rp->target,
rp->do_get,
rp->implicit,
rp->target->has_target_prop ? true : false) !=
build_running) &&
!commands_done) {
commands_done =
saved_commands_done;
}
rp->target->dont_activate_cond_values = false;
reset_conditionals
(rp->conditional_cnt,
rp->conditional_targets,
conditionals);
quiescent = false;
delete_running_struct(rp);
goto start_loop_2;
} else {
rp_prev = &rp->next;
}
} else {
rp_prev = &rp->next;
}
} else {
rp_prev = &rp->next;
}
}
if (quiescent) {
start_loop_3:
for (rp_prev = &running_list, rp = running_list;
rp != NULL;
rp = rp->next) {
if (rp->state == build_subtree) {
if (!dependency_conflict(rp->target)) {
*rp_prev = rp->next;
if (rp->next == NULL) {
running_tail = rp_prev;
}
recursion_level = rp->recursion_level;
doname_subtree(rp->target,
rp->do_get,
rp->implicit);
quiescent = false;
delete_running_struct(rp);
goto start_loop_3;
} else {
subtree_target = rp_prev;
rp_prev = &rp->next;
}
} else {
rp_prev = &rp->next;
}
}
}
if (quiescent) {
if (subtree_target == NULL) {
fatal(gettext("Internal error: deadlock detected in process_next"));
} else {
rp = *subtree_target;
if (debug_level > 0) {
warning(gettext("Conditional macro conflict encountered for %s between %s and %s"),
subtree_conflict2->string_mb,
rp->target->string_mb,
subtree_conflict->string_mb);
}
*subtree_target = (*subtree_target)->next;
if (rp->next == NULL) {
running_tail = subtree_target;
}
recursion_level = rp->recursion_level;
doname_subtree(rp->target, rp->do_get, rp->implicit);
delete_running_struct(rp);
}
}
}
static Property *
set_conditionals(int cnt, Name *targets)
{
Property *locals, *lp;
Name *tp;
locals = (Property *) getmem(cnt * sizeof(Property));
for (lp = locals, tp = targets;
cnt > 0;
cnt--, lp++, tp++) {
*lp = (Property) getmem((*tp)->conditional_cnt *
sizeof(struct _Property));
set_locals(*tp, *lp);
}
return locals;
}
static void
reset_conditionals(int cnt, Name *targets, Property *locals)
{
Name *tp;
Property *lp;
for (tp = targets + (cnt - 1), lp = locals + (cnt - 1);
cnt > 0;
cnt--, tp--, lp--) {
reset_locals(*tp,
*lp,
get_prop((*tp)->prop, conditional_prop),
0);
retmem_mb((caddr_t) *lp);
}
retmem_mb((caddr_t) locals);
}
static Boolean
dependency_conflict(Name target)
{
Property line;
Property pending_line;
Dependency dp;
Dependency pending_dp;
Running rp;
if (target->checking_subtree) {
return false;
}
target->checking_subtree = true;
line = get_prop(target->prop, line_prop);
if (line == NULL) {
target->checking_subtree = false;
return false;
}
for (dp = line->body.line.dependencies; dp != NULL; dp = dp->next) {
if (dp->name == wait_name) {
continue;
}
for (rp = running_list; rp != NULL; rp = rp->next) {
if (rp->state == build_pending) {
pending_line = get_prop(rp->target->prop,
line_prop);
if (pending_line == NULL) {
continue;
}
for(pending_dp = pending_line->
body.line.dependencies;
pending_dp != NULL;
pending_dp = pending_dp->next) {
if (dp->name == pending_dp->name) {
target->checking_subtree
= false;
subtree_conflict = rp->target;
subtree_conflict2 = dp->name;
return true;
}
}
}
}
if (dependency_conflict(dp->name)) {
target->checking_subtree = false;
return true;
}
}
target->checking_subtree = false;
return false;
}
void
await_parallel(Boolean waitflg)
{
Boolean nohang;
pid_t pid;
int status;
Running rp;
int waiterr;
nohang = false;
for ( ; ; ) {
if (!nohang) {
(void) alarm((int) update_delay);
}
pid = waitpid((pid_t)-1,
&status,
nohang ? WNOHANG : 0);
waiterr = errno;
if (!nohang) {
(void) alarm(0);
}
if (pid <= 0) {
if (waiterr == EINTR) {
if (waitflg) {
continue;
} else {
return;
}
} else {
return;
}
}
for (rp = running_list;
(rp != NULL) && (rp->pid != pid);
rp = rp->next) {
;
}
if (rp == NULL) {
fatal(gettext("Internal error: returned child pid not in running_list"));
} else {
rp->state = (WIFEXITED(status) && WEXITSTATUS(status) == 0) ? build_ok : build_failed;
}
nohang = true;
parallel_process_cnt--;
if (job_adjust_mode == ADJUST_M2) {
if (m2_release_job()) {
job_adjust_error();
}
}
}
}
void
finish_children(Boolean docheck)
{
int cmds_length;
Property line;
Property line2;
struct stat out_buf;
Running rp;
Running *rp_prev;
Cmd_line rule;
Boolean silent_flag;
for (rp_prev = &running_list, rp = running_list;
rp != NULL;
rp = rp->next) {
bypass_for_loop_inc_4:
if (rp->state == build_ok || rp->state == build_failed) {
*rp_prev = rp->next;
if (rp->next == NULL) {
running_tail = rp_prev;
}
if ((line2 = rp->command) == NULL) {
line2 = get_prop(rp->target->prop, line_prop);
}
if (rp->stdout_file != NULL) {
if (stat(rp->stdout_file, &out_buf) < 0) {
fatal(gettext("stat of %s failed: %s"),
rp->stdout_file,
errmsg(errno));
}
if ((line2 != NULL) &&
(out_buf.st_size > 0)) {
cmds_length = 0;
for (rule = line2->body.line.command_used,
silent_flag = silent;
rule != NULL;
rule = rule->next) {
cmds_length += rule->command_line->hash.length + 1;
silent_flag = BOOLEAN(silent_flag || rule->silent);
}
if (out_buf.st_size != cmds_length || silent_flag ||
output_mode == txt2_mode) {
dump_out_file(rp->stdout_file, false);
}
}
(void) unlink(rp->stdout_file);
retmem_mb(rp->stdout_file);
rp->stdout_file = NULL;
}
if (!out_err_same && (rp->stderr_file != NULL)) {
if (stat(rp->stderr_file, &out_buf) < 0) {
fatal(gettext("stat of %s failed: %s"),
rp->stderr_file,
errmsg(errno));
}
if ((line2 != NULL) &&
(out_buf.st_size > 0)) {
dump_out_file(rp->stderr_file, true);
}
(void) unlink(rp->stderr_file);
retmem_mb(rp->stderr_file);
rp->stderr_file = NULL;
}
check_state(rp->temp_file);
if (rp->temp_file != NULL) {
free_name(rp->temp_file);
}
rp->temp_file = NULL;
if (rp->state == build_failed) {
line = get_prop(rp->target->prop, line_prop);
if (line != NULL) {
line->body.line.command_used = NULL;
}
if (continue_after_error ||
fatal_in_progress ||
!docheck) {
warning(gettext("Command failed for target `%s'"),
rp->command ? line2->body.line.target->string_mb : rp->target->string_mb);
build_failed_seen = true;
} else {
#ifdef PRINT_EXIT_STATUS
warning("I'm in finish_children. rp->state == build_failed.");
#endif
fatal(gettext("Command failed for target `%s'"),
rp->command ? line2->body.line.target->string_mb : rp->target->string_mb);
}
}
if (!docheck) {
delete_running_struct(rp);
rp = *rp_prev;
if (rp == NULL) {
break;
} else {
goto bypass_for_loop_inc_4;
}
}
update_target(get_prop(rp->target->prop, line_prop),
rp->state);
finish_doname(rp);
delete_running_struct(rp);
rp = *rp_prev;
if (rp == NULL) {
break;
} else {
goto bypass_for_loop_inc_4;
}
} else {
rp_prev = &rp->next;
}
}
}
static void
dump_out_file(char *filename, Boolean err)
{
int chars_read;
char copybuf[BUFSIZ];
int fd;
int out_fd = (err ? 2 : 1);
if ((fd = open(filename, O_RDONLY)) < 0) {
fatal(gettext("open failed for output file %s: %s"),
filename,
errmsg(errno));
}
if (!silent && output_mode != txt2_mode) {
(void) fprintf(err ? stderr : stdout,
err ?
gettext("%s --> Job errors\n") :
gettext("%s --> Job output\n"),
local_host);
(void) fflush(err ? stderr : stdout);
}
for (chars_read = read(fd, copybuf, BUFSIZ);
chars_read > 0;
chars_read = read(fd, copybuf, BUFSIZ)) {
if (write(out_fd, copybuf, chars_read) < 0) {
fatal(gettext("write failed for output file %s: %s"),
filename,
errmsg(errno));
}
}
(void) close(fd);
(void) unlink(filename);
}
static void
finish_doname(Running rp)
{
int auto_count = rp->auto_count;
Name *automatics = rp->automatics;
Doname result = rp->state;
Name target = rp->target;
Name true_target = rp->true_target;
Property *conditionals;
recursion_level = rp->recursion_level;
if (result == build_ok) {
if (true_target == NULL) {
(void) printf("Target = %s\n", target->string_mb);
(void) printf(" State = %d\n", result);
fatal("Internal error: NULL true_target in finish_doname");
}
if (true_target->stat.time == file_doesnt_exist) {
true_target->stat.time = file_max_time;
}
}
target->state = result;
if (target->is_member) {
Property member;
if ((target->stat.time != file_max_time) &&
((member = get_prop(target->prop, member_prop)) != NULL) &&
(exists(member->body.member.member) > file_doesnt_exist)) {
target->stat.time =
member->body.member.member->stat.time;
}
}
if ((result == build_ok) && check_auto_dependencies(target,
auto_count,
automatics)) {
if (debug_level > 0) {
(void) printf(gettext("%*sTarget `%s' acquired new dependencies from build, checking all dependencies\n"),
recursion_level,
"",
true_target->string_mb);
}
target->rechecking_target = true;
target->state = build_running;
conditionals = set_conditionals(rp->conditional_cnt, rp->conditional_targets);
add_pending(target,
recursion_level,
rp->do_get,
rp->implicit,
true);
reset_conditionals(rp->conditional_cnt, rp->conditional_targets, conditionals);
}
}
static Running new_running_struct()
{
Running rp;
rp = ALLOC(Running);
rp->target = NULL;
rp->true_target = NULL;
rp->command = NULL;
rp->sprodep_value = NULL;
rp->sprodep_env = NULL;
rp->auto_count = 0;
rp->automatics = NULL;
rp->pid = -1;
rp->job_msg_id = -1;
rp->stdout_file = NULL;
rp->stderr_file = NULL;
rp->temp_file = NULL;
rp->next = NULL;
return rp;
}
void
add_running(Name target, Name true_target, Property command, int recursion_level, int auto_count, Name *automatics, Boolean do_get, Boolean implicit)
{
Running rp;
Name *p;
rp = new_running_struct();
rp->state = build_running;
rp->target = target;
rp->true_target = true_target;
rp->command = command;
rp->recursion_level = recursion_level;
rp->do_get = do_get;
rp->implicit = implicit;
rp->auto_count = auto_count;
if (auto_count > 0) {
rp->automatics = (Name *) getmem(auto_count * sizeof (Name));
for (p = rp->automatics; auto_count > 0; auto_count--) {
*p++ = *automatics++;
}
} else {
rp->automatics = NULL;
}
{
rp->pid = process_running;
process_running = -1;
childPid = -1;
}
rp->job_msg_id = job_msg_id;
rp->stdout_file = stdout_file;
rp->stderr_file = stderr_file;
rp->temp_file = temp_file_name;
rp->redo = false;
rp->next = NULL;
store_conditionals(rp);
stdout_file = NULL;
stderr_file = NULL;
temp_file_name = NULL;
current_target = NULL;
current_line = NULL;
*running_tail = rp;
running_tail = &rp->next;
}
void
add_pending(Name target, int recursion_level, Boolean do_get, Boolean implicit, Boolean redo)
{
Running rp;
rp = new_running_struct();
rp->state = build_pending;
rp->target = target;
rp->recursion_level = recursion_level;
rp->do_get = do_get;
rp->implicit = implicit;
rp->redo = redo;
store_conditionals(rp);
*running_tail = rp;
running_tail = &rp->next;
}
void
add_serial(Name target, int recursion_level, Boolean do_get, Boolean implicit)
{
Running rp;
rp = new_running_struct();
rp->target = target;
rp->recursion_level = recursion_level;
rp->do_get = do_get;
rp->implicit = implicit;
rp->state = build_serial;
rp->redo = false;
store_conditionals(rp);
*running_tail = rp;
running_tail = &rp->next;
}
void
add_subtree(Name target, int recursion_level, Boolean do_get, Boolean implicit)
{
Running rp;
rp = new_running_struct();
rp->target = target;
rp->recursion_level = recursion_level;
rp->do_get = do_get;
rp->implicit = implicit;
rp->state = build_subtree;
rp->redo = false;
store_conditionals(rp);
*running_tail = rp;
running_tail = &rp->next;
}
static void
store_conditionals(Running rp)
{
int cnt;
Chain cond_name;
if (conditional_targets == NULL) {
rp->conditional_cnt = 0;
rp->conditional_targets = NULL;
return;
}
cnt = 0;
for (cond_name = conditional_targets;
cond_name != NULL;
cond_name = cond_name->next) {
cnt++;
}
rp->conditional_cnt = cnt;
rp->conditional_targets = (Name *) getmem(cnt * sizeof(Name));
for (cond_name = conditional_targets;
cond_name != NULL;
cond_name = cond_name->next) {
rp->conditional_targets[--cnt] = cond_name->name;
}
}
Boolean
parallel_ok(Name target, Boolean line_prop_must_exists)
{
Boolean assign;
Boolean make_refd;
Property line;
Cmd_line rule;
assign = make_refd = false;
if (((line = get_prop(target->prop, line_prop)) == NULL) &&
line_prop_must_exists) {
return false;
}
if (line != NULL) {
for (rule = line->body.line.command_used;
rule != NULL;
rule = rule->next) {
if (rule->assign) {
assign = true;
} else if (rule->make_refd) {
make_refd = true;
}
}
}
if (assign) {
return false;
} else if (target->parallel) {
return true;
} else if (target->no_parallel) {
return false;
} else if (all_parallel) {
return true;
} else if (only_parallel) {
return false;
} else if (make_refd) {
return false;
} else {
return true;
}
}
Boolean
is_running(Name target)
{
Running rp;
if (target->state != build_running) {
return false;
}
for (rp = running_list;
rp != NULL && target != rp->target;
rp = rp->next);
if (rp == NULL) {
return false;
} else {
return (rp->state == build_running) ? true : false;
}
}
static pid_t
run_rule_commands(char *host, char **commands)
{
Boolean always_exec;
Name command;
Boolean ignore;
int length;
Doname result;
Boolean silent_flag;
wchar_t *tmp_wcs_buffer;
childPid = fork();
switch (childPid) {
case -1:
fatal(gettext("Could not fork child process for dmake job: %s"),
errmsg(errno));
break;
case 0:
running_list = NULL;
if(out_err_same) {
redirect_io(stdout_file, (char*)NULL);
} else {
redirect_io(stdout_file, stderr_file);
}
for (commands = commands;
(*commands != (char *)NULL);
commands++) {
silent_flag = silent;
ignore = false;
always_exec = false;
while ((**commands == (int) at_char) ||
(**commands == (int) hyphen_char) ||
(**commands == (int) plus_char)) {
if (**commands == (int) at_char) {
silent_flag = true;
}
if (**commands == (int) hyphen_char) {
ignore = true;
}
if (**commands == (int) plus_char) {
always_exec = true;
}
(*commands)++;
}
if ((length = strlen(*commands)) >= MAXPATHLEN) {
tmp_wcs_buffer = ALLOC_WC(length + 1);
(void) mbstowcs(tmp_wcs_buffer, *commands, length + 1);
command = GETNAME(tmp_wcs_buffer, FIND_LENGTH);
retmem(tmp_wcs_buffer);
} else {
MBSTOWCS(wcs_buffer, *commands);
command = GETNAME(wcs_buffer, FIND_LENGTH);
}
if ((command->hash.length > 0) &&
!silent_flag) {
(void) printf("%s\n", command->string_mb);
}
result = dosys(command,
ignore,
false,
false,
always_exec,
(Name) NULL);
if (result == build_failed) {
if (silent_flag) {
(void) printf(gettext("The following command caused the error:\n%s\n"), command->string_mb);
}
if (!ignore) {
_exit(1);
}
}
}
_exit(0);
break;
default:
break;
}
return childPid;
}
static void
maybe_reread_make_state(void)
{
if (report_dependencies_level == 0) {
make_state->stat.time = file_no_time;
(void) exists(make_state);
if (make_state_before == make_state->stat.time) {
return;
}
makefile_type = reading_statefile;
if (read_trace_level > 1) {
trace_reader = true;
}
temp_file_number++;
(void) read_simple_file(make_state,
false,
false,
false,
false,
false,
true);
trace_reader = false;
}
}
static void
delete_running_struct(Running rp)
{
if ((rp->conditional_cnt > 0) &&
(rp->conditional_targets != NULL)) {
retmem_mb((char *) rp->conditional_targets);
}
if ((rp->auto_count > 0) &&
(rp->automatics != NULL)) {
retmem_mb((char *) rp->automatics);
}
if(rp->sprodep_value) {
free_name(rp->sprodep_value);
}
if(rp->sprodep_env) {
retmem_mb(rp->sprodep_env);
}
retmem_mb((char *) rp);
}