Remake
Loading...
Searching...
No Matches
Functions
Server

Functions

static void complete_job (int job_id, bool success, bool started=true)
 
static std::string prepare_script (job_t const &job)
 
static status_e run_script (int job_id, job_t const &job)
 
static status_e start (std::string const &target, client_list::iterator &current)
 
static void complete_request (client_t &client, bool success)
 
static bool has_free_slots ()
 
static bool handle_clients ()
 
static void create_server ()
 
static void accept_client ()
 
static void finalize_job (pid_t pid, bool res)
 
static void server_loop ()
 
static void server_mode (std::string const &remakefile, string_list const &targets)
 

Detailed Description

Function Documentation

◆ accept_client()

static void accept_client ( )
static

Accept a connection from a client, get the job it spawned from, get the targets, and mark them as dependencies of the job targets.

Definition at line 2691 of file remake.cpp.

2692{
2693 DEBUG_open << "Handling client request... ";
2694
2695 // Accept connection.
2696#ifdef WINDOWS
2698 if (fd == INVALID_SOCKET) return;
2700 {
2701 error2:
2702 std::cerr << "Unexpected failure while setting connection with client" << std::endl;
2703 closesocket(fd);
2704 return;
2705 }
2706 // WSAEventSelect puts sockets into nonblocking mode, so disable it here.
2707 u_long nbio = 0;
2708 if (ioctlsocket(fd, FIONBIO, &nbio)) goto error2;
2709#elif defined(LINUX)
2711 if (fd < 0) return;
2712#else
2713 int fd = accept(socket_fd, NULL, NULL);
2714 if (fd < 0) return;
2715 if (fcntl(fd, F_SETFD, FD_CLOEXEC) < 0) return;
2716#endif
2717 clients.push_front(client_t());
2718 client_list::iterator proc = clients.begin();
2719
2720 if (false)
2721 {
2722 error:
2723 DEBUG_close << "failed\n";
2724 std::cerr << "Received an ill-formed client message" << std::endl;
2725 #ifdef WINDOWS
2726 closesocket(fd);
2727 #else
2728 close(fd);
2729 #endif
2730 clients.erase(proc);
2731 return;
2732 }
2733
2734 // Receive message. Stop when encountering two nuls in a row.
2735 std::vector<char> buf;
2736 size_t len = 0;
2737 while (len < sizeof(int) + 2 || buf[len - 1] || buf[len - 2])
2738 {
2739 buf.resize(len + 1024);
2740 ssize_t l = recv(fd, &buf[0] + len, 1024, 0);
2741 if (l <= 0) goto error;
2742 len += l;
2743 }
2744
2745 // Parse job that spawned the client.
2746 int job_id;
2747 memcpy(&job_id, &buf[0], sizeof(int));
2748 proc->socket = fd;
2749 proc->job_id = job_id;
2750 job_map::const_iterator i = jobs.find(job_id);
2751 if (i == jobs.end()) goto error;
2752 DEBUG << "receiving request from job " << job_id << std::endl;
2753 if (propagate_vars) proc->vars = i->second.vars;
2754
2755 // Parse the targets and the variable assignments.
2756 // Mark the targets as dependencies of the job targets.
2757 dependency_t &dep = *dependencies[i->second.rule.targets.front()];
2759 char const *p = &buf[0] + sizeof(int);
2760 while (true)
2761 {
2762 len = strlen(p);
2763 if (len == 0)
2764 {
2765 ++waiting_jobs;
2766 break;
2767 }
2768 switch (*p)
2769 {
2770 case 'T':
2771 {
2772 if (len == 1) goto error;
2773 std::string target(p + 1, p + len);
2774 DEBUG << "adding dependency " << target << " to job\n";
2775 proc->pending.push_back(target);
2776 dep.deps.insert(target);
2777 break;
2778 }
2779 case 'V':
2780 {
2781 if (len == 1) goto error;
2782 std::string var(p + 1, p + len);
2783 DEBUG << "adding variable " << var << " to job\n";
2784 last_var = &proc->vars[var];
2785 last_var->clear();
2786 break;
2787 }
2788 case 'W':
2789 {
2790 if (!last_var) goto error;
2791 last_var->push_back(std::string(p + 1, p + len));
2792 break;
2793 }
2794 default:
2795 goto error;
2796 }
2797 p += len + 1;
2798 }
2799
2800 if (!propagate_vars && !proc->vars.empty())
2801 {
2802 std::cerr << "Assignments are ignored unless 'variable-propagation' is enabled" << std::endl;
2803 proc->vars.clear();
2804 }
2805}
@ INVALID_SOCKET
Definition remake.cpp:463
int socket_t
Definition remake.cpp:462
static client_list clients
Definition remake.cpp:655
static int waiting_jobs
Definition remake.cpp:688
std::list< std::string > string_list
Definition remake.cpp:471
#define DEBUG_close
Definition remake.cpp:819
static dependency_map dependencies
Definition remake.cpp:624
static job_map jobs
Definition remake.cpp:644
#define DEBUG_open
Definition remake.cpp:818
#define DEBUG
Definition remake.cpp:817
static socket_t socket_fd
Definition remake.cpp:699
static bool propagate_vars
Definition remake.cpp:751

Referenced by server_loop().

◆ complete_job()

static void complete_job ( int job_id,
bool success,
bool started = true )
static

Handle job completion.

Definition at line 2133 of file remake.cpp.

2134{
2135 DEBUG << "Completing job " << job_id << '\n';
2136 job_map::iterator i = jobs.find(job_id);
2137 assert(i != jobs.end());
2138 string_list const &targets = i->second.rule.targets;
2139 if (success)
2140 {
2141 bool show = show_targets && started;
2142 if (show) std::cout << "Finished";
2143 for (string_list::const_iterator j = targets.begin(),
2144 j_end = targets.end(); j != j_end; ++j)
2145 {
2146 update_status(*j);
2147 if (show) std::cout << ' ' << *j;
2148 }
2149 if (show) std::cout << std::endl;
2150 }
2151 else
2152 {
2153 std::cerr << "Failed to build";
2154 for (string_list::const_iterator j = targets.begin(),
2155 j_end = targets.end(); j != j_end; ++j)
2156 {
2157 std::cerr << ' ' << *j;
2158 update_status(*j);
2159 status_e &s = status[*j].status;
2160 if (s != Uptodate)
2161 {
2162 DEBUG << "Removing " << *j << '\n';
2163 remove(j->c_str());
2164 }
2165 s = Failed;
2166 }
2167 std::cerr << std::endl;
2168 }
2169 jobs.erase(i);
2170}
static void update_status(std::string const &target)
Definition remake.cpp:2066
static status_map status
Definition remake.cpp:629
status_e
Definition remake.cpp:525
@ Failed
Build failed for target.
Definition remake.cpp:532
@ Uptodate
Target is up-to-date.
Definition remake.cpp:526
static bool show_targets
Definition remake.cpp:721

Referenced by complete_request(), finalize_job(), and run_script().

◆ complete_request()

static void complete_request ( client_t & client,
bool success )
static

Send a reply to a client then remove it. If the client was a dependency client, start the actual script.

Definition at line 2438 of file remake.cpp.

2439{
2440 DEBUG_open << "Completing request from client of job " << client.job_id << "... ";
2441 if (client.delayed)
2442 {
2443 assert(client.socket == INVALID_SOCKET);
2444 if (success)
2445 {
2446 job_map::const_iterator i = jobs.find(client.job_id);
2447 assert(i != jobs.end());
2448 if (still_need_rebuild(i->second.rule.targets.front()))
2449 run_script(client.job_id, i->second);
2450 else complete_job(client.job_id, true, false);
2451 }
2452 else complete_job(client.job_id, false);
2453 }
2454 else if (client.socket != INVALID_SOCKET)
2455 {
2456 char res = success ? 1 : 0;
2457 send(client.socket, &res, 1, MSG_NOSIGNAL);
2458 #ifdef WINDOWS
2459 closesocket(client.socket);
2460 #else
2461 close(client.socket);
2462 #endif
2463 --waiting_jobs;
2464 }
2465
2466 if (client.job_id < 0 && !success) build_failure = true;
2467}
static status_e run_script(int job_id, job_t const &job)
Definition remake.cpp:2258
static void complete_job(int job_id, bool success, bool started=true)
Definition remake.cpp:2133
static bool still_need_rebuild(std::string const &target)
Definition remake.cpp:2099
static bool build_failure
Definition remake.cpp:704
socket_t socket
Socket used to reply to the client (invalid for pseudo clients).
Definition remake.cpp:603
bool delayed
Whether it is a dependency client and a script has to be started on request completion.
Definition remake.cpp:609
int job_id
Job for which the built script called remake and spawned the client (negative for original clients).
Definition remake.cpp:604

Referenced by handle_clients().

◆ create_server()

static void create_server ( )
static

Create a named unix socket that listens for build requests. Also set the REMAKE_SOCKET environment variable that will be inherited by all the job scripts.

Definition at line 2611 of file remake.cpp.

2612{
2613 if (false)
2614 {
2615 error:
2616 perror("Failed to create server");
2617#ifndef WINDOWS
2618 error2:
2619#endif
2621 }
2622 DEBUG_open << "Creating server... ";
2623
2624#ifdef WINDOWS
2625 // Prepare a windows socket.
2626 struct sockaddr_in socket_addr;
2627 socket_addr.sin_family = AF_INET;
2628 socket_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
2629 socket_addr.sin_port = 0;
2630
2631 // Create and listen to the socket.
2632 socket_fd = socket(AF_INET, SOCK_STREAM, 0);
2633 if (socket_fd == INVALID_SOCKET) goto error;
2635 goto error;
2636 if (bind(socket_fd, (struct sockaddr *)&socket_addr, sizeof(sockaddr_in)))
2637 goto error;
2638 int len = sizeof(sockaddr_in);
2639 if (getsockname(socket_fd, (struct sockaddr *)&socket_addr, &len))
2640 goto error;
2641 std::ostringstream buf;
2642 buf << socket_addr.sin_port;
2643 if (!SetEnvironmentVariable("REMAKE_SOCKET", buf.str().c_str()))
2644 goto error;
2645 if (listen(socket_fd, 1000)) goto error;
2646#else
2647 // Set signal handlers for SIGCHLD and SIGINT.
2648 // Block SIGCHLD (unblocked during select).
2652 if (sigprocmask(SIG_BLOCK, &sigmask, &old_sigmask) == -1) goto error;
2653 struct sigaction sa;
2654 sa.sa_flags = 0;
2655 sigemptyset(&sa.sa_mask);
2656 sa.sa_handler = &sigchld_handler;
2657 if (sigaction(SIGCHLD, &sa, NULL) == -1) goto error;
2658 sa.sa_handler = &sigint_handler;
2659 if (sigaction(SIGINT, &sa, NULL) == -1) goto error;
2660
2661 // Prepare a named unix socket in temporary directory.
2662 socket_name = tempnam(NULL, "rmk-");
2663 if (!socket_name) goto error2;
2664 struct sockaddr_un socket_addr;
2665 size_t len = strlen(socket_name);
2666 if (len >= sizeof(socket_addr.sun_path) - 1) goto error2;
2667 socket_addr.sun_family = AF_UNIX;
2668 strcpy(socket_addr.sun_path, socket_name);
2669 len += sizeof(socket_addr.sun_family);
2670 if (setenv("REMAKE_SOCKET", socket_name, 1)) goto error;
2671
2672 // Create and listen to the socket.
2673#ifdef LINUX
2674 socket_fd = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0);
2675 if (socket_fd == INVALID_SOCKET) goto error;
2676#else
2677 socket_fd = socket(AF_UNIX, SOCK_STREAM, 0);
2678 if (socket_fd == INVALID_SOCKET) goto error;
2679 if (fcntl(socket_fd, F_SETFD, FD_CLOEXEC) < 0) goto error;
2680#endif
2681 if (bind(socket_fd, (struct sockaddr *)&socket_addr, len))
2682 goto error;
2683 if (listen(socket_fd, 1000)) goto error;
2684#endif
2685}
static void sigchld_handler(int)
Definition remake.cpp:763
static char * socket_name
Definition remake.cpp:710
static sigset_t old_sigmask
Definition remake.cpp:759
static void sigint_handler(int)
Definition remake.cpp:768
ref_ptr()
Definition remake.cpp:491

Referenced by server_mode().

◆ finalize_job()

static void finalize_job ( pid_t pid,
bool res )
static

Handle child process exit status.

Definition at line 2810 of file remake.cpp.

2811{
2812 pid_job_map::iterator i = job_pids.find(pid);
2813 assert(i != job_pids.end());
2814 int job_id = i->second;
2815 job_pids.erase(i);
2816 --running_jobs;
2817 complete_job(job_id, res);
2818}
static pid_job_map job_pids
Definition remake.cpp:649
static int running_jobs
Definition remake.cpp:680

Referenced by server_loop().

◆ handle_clients()

static bool handle_clients ( )
static

Handle client requests:

  • check for running targets that have finished,
  • start as many pending targets as allowed,
  • complete the request if there are neither running nor pending targets left or if any of them failed.
Returns
true if some child processes are still running.
Postcondition
If there are pending requests, at least one child process is running.
Invariant
New free slots cannot appear during a run, since the only way to decrease running_jobs is finalize_job and the only way to increase waiting_jobs is accept_client. None of these functions are called during a run. So breaking out as soon as there are no free slots left is fine.

Definition at line 2495 of file remake.cpp.

2496{
2497 DEBUG_open << "Handling client requests... ";
2498 restart:
2499 bool need_restart = false;
2500
2501 for (client_list::iterator i = clients.begin(), i_next = i,
2502 i_end = clients.end(); i != i_end; i = i_next)
2503 {
2504 if (!has_free_slots()) break;
2505 ++i_next;
2506 DEBUG_open << "Handling client from job " << i->job_id << "... ";
2507
2508 // Remove running targets that have finished.
2509 for (string_set::iterator j = i->running.begin(), j_next = j,
2510 j_end = i->running.end(); j != j_end; j = j_next)
2511 {
2512 ++j_next;
2513 status_map::const_iterator k = status.find(*j);
2514 assert(k != status.end());
2515 switch (k->second.status)
2516 {
2517 case Running:
2518 case RunningRecheck:
2519 break;
2520 case Failed:
2521 i->failed = true;
2522 if (!keep_going) goto complete;
2523 // fallthrough
2524 case Uptodate:
2525 case Remade:
2526 i->running.erase(j);
2527 break;
2528 case Recheck:
2529 case Todo:
2530 assert(false);
2531 }
2532 }
2533
2534 // Start pending targets.
2535 while (!i->pending.empty())
2536 {
2537 std::string target = i->pending.front();
2538 i->pending.pop_front();
2539 switch (get_status(target).status)
2540 {
2541 case Running:
2542 case RunningRecheck:
2543 i->running.insert(target);
2544 break;
2545 case Failed:
2547 i->failed = true;
2548 if (!keep_going) goto complete;
2549 // fallthrough
2550 case Uptodate:
2551 case Remade:
2552 break;
2553 case Recheck:
2554 case Todo:
2555 client_list::iterator j = i;
2556 switch (start(target, i))
2557 {
2558 case Failed:
2559 goto pending_failed;
2560 case Running:
2561 // A shell was started, check for free slots.
2562 j->running.insert(target);
2563 if (!has_free_slots()) return true;
2564 break;
2565 case RunningRecheck:
2566 // Switch to the dependency client that was inserted.
2567 j->running.insert(target);
2568 i_next = j;
2569 break;
2570 case Remade:
2571 // Nothing to run.
2572 need_restart = true;
2573 break;
2574 default:
2575 assert(false);
2576 }
2577 }
2578 }
2579
2580 // Try to complete the request.
2581 // (This might start a new job if it was a dependency client.)
2582 if (i->running.empty() || i->failed)
2583 {
2584 complete:
2585 complete_request(*i, !i->failed);
2586 DEBUG_close << (i->failed ? "failed\n" : "finished\n");
2587 clients.erase(i);
2588 need_restart = true;
2589 }
2590 }
2591
2592 if (running_jobs != waiting_jobs) return true;
2593 if (running_jobs == 0 && clients.empty()) return false;
2594 if (need_restart) goto restart;
2595
2596 // There is a circular dependency.
2597 // Try to break it by completing one of the requests.
2598 assert(!clients.empty());
2599 std::cerr << "Circular dependency detected" << std::endl;
2600 client_list::iterator i = clients.begin();
2601 complete_request(*i, false);
2602 clients.erase(i);
2603 goto restart;
2604}
static void complete_request(client_t &client, bool success)
Definition remake.cpp:2438
static status_e start(std::string const &target, client_list::iterator &current)
Definition remake.cpp:2380
static bool has_free_slots()
Definition remake.cpp:2472
static status_t const & get_status(std::string const &target)
Definition remake.cpp:1989
static bool keep_going
Definition remake.cpp:667
@ Todo
Target is missing or obsolete.
Definition remake.cpp:527
@ Running
Target is being rebuilt.
Definition remake.cpp:529
@ Recheck
Target has an obsolete dependency.
Definition remake.cpp:528
@ Remade
Target was successfully rebuilt.
Definition remake.cpp:531
@ RunningRecheck
Static prerequisites are being rebuilt.
Definition remake.cpp:530

Referenced by server_loop().

◆ has_free_slots()

static bool has_free_slots ( )
static

Return whether there are slots for starting new jobs.

Definition at line 2472 of file remake.cpp.

2473{
2474 if (max_active_jobs <= 0) return true;
2476}
static int max_active_jobs
Definition remake.cpp:661

Referenced by handle_clients().

◆ prepare_script()

static std::string prepare_script ( job_t const & job)
static

Return the script obtained by substituting variables.

Definition at line 2175 of file remake.cpp.

2176{
2177 std::string const &s = job.rule.script;
2178 std::istringstream in(s);
2179 std::ostringstream out;
2180 size_t len = s.size();
2181
2182 while (!in.eof())
2183 {
2184 size_t pos = in.tellg(), p = s.find('$', pos);
2185 if (p == std::string::npos || p == len - 1) p = len;
2186 out.write(&s[pos], p - pos);
2187 if (p == len) break;
2188 ++p;
2189 switch (s[p])
2190 {
2191 case '$':
2192 out << '$';
2193 in.seekg(p + 1);
2194 break;
2195 case '<':
2196 if (!job.rule.deps.empty())
2197 out << job.rule.deps.front();
2198 in.seekg(p + 1);
2199 break;
2200 case '^':
2201 {
2202 bool first = true;
2203 for (string_list::const_iterator i = job.rule.deps.begin(),
2204 i_end = job.rule.deps.end(); i != i_end; ++i)
2205 {
2206 if (first) first = false;
2207 else out << ' ';
2208 out << *i;
2209 }
2210 in.seekg(p + 1);
2211 break;
2212 }
2213 case '@':
2214 assert(!job.rule.targets.empty());
2215 out << job.rule.targets.front();
2216 in.seekg(p + 1);
2217 break;
2218 case '*':
2219 out << job.rule.stem;
2220 in.seekg(p + 1);
2221 break;
2222 case '(':
2223 {
2224 in.seekg(p - 1);
2225 bool first = true;
2226 input_generator gen(in, &job.vars, true);
2227 while (true)
2228 {
2229 std::string w;
2230 input_status s = gen.next(w);
2231 if (s == SyntaxError)
2232 {
2233 // TODO
2234 return "false";
2235 }
2236 if (s == Eof) break;
2237 if (first) first = false;
2238 else out << ' ';
2239 out << w;
2240 }
2241 break;
2242 }
2243 default:
2244 // Let dollars followed by an unrecognized character
2245 // go through. This differs from Make, which would
2246 // use a one-letter variable.
2247 out << '$';
2248 in.seekg(p);
2249 }
2250 }
2251
2252 return out.str();
2253}
input_status
Definition remake.cpp:1175
@ SyntaxError
Definition remake.cpp:1177
@ Eof
Definition remake.cpp:1178

Referenced by run_script().

◆ run_script()

static status_e run_script ( int job_id,
job_t const & job )
static

Execute the script from rule.

Definition at line 2258 of file remake.cpp.

2259{
2261 dep->targets = job.rule.targets;
2262 dep->deps.insert(job.rule.deps.begin(), job.rule.deps.end());
2263 if (show_targets) std::cout << "Building";
2264 for (string_list::const_iterator i = job.rule.targets.begin(),
2265 i_end = job.rule.targets.end(); i != i_end; ++i)
2266 {
2267 dependencies[*i] = dep;
2268 if (show_targets) std::cout << ' ' << *i;
2269 }
2270 if (show_targets) std::cout << std::endl;
2271
2272 std::string script = prepare_script(job);
2273
2274 std::ostringstream job_id_buf;
2275 job_id_buf << job_id;
2276 std::string job_id_ = job_id_buf.str();
2277
2278 DEBUG_open << "Starting script for job " << job_id << "... ";
2279 if (script.empty())
2280 {
2281 DEBUG_close << "no script\n";
2282 complete_job(job_id, true);
2283 return Remade;
2284 }
2285
2286 if (false)
2287 {
2288 error:
2289 DEBUG_close << "failed\n";
2290 complete_job(job_id, false);
2291 return Failed;
2292 }
2293
2294#ifdef WINDOWS
2295 HANDLE pfd[2];
2296 if (false)
2297 {
2298 error2:
2299 CloseHandle(pfd[0]);
2300 CloseHandle(pfd[1]);
2301 goto error;
2302 }
2303 if (!CreatePipe(&pfd[0], &pfd[1], NULL, 0))
2304 goto error;
2306 goto error2;
2308 ZeroMemory(&si, sizeof(STARTUPINFO));
2309 si.cb = sizeof(STARTUPINFO);
2310 si.hStdError = GetStdHandle(STD_ERROR_HANDLE);
2311 si.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
2312 si.hStdInput = pfd[0];
2313 si.dwFlags |= STARTF_USESTDHANDLES;
2316 if (!SetEnvironmentVariable("REMAKE_JOB_ID", job_id_.c_str()))
2317 goto error2;
2318 char const *argv = echo_scripts ? "SH.EXE -e -s -v" : "SH.EXE -e -s";
2319 if (!CreateProcess(NULL, (char *)argv, NULL, NULL,
2320 true, 0, NULL, NULL, &si, &pi))
2321 {
2322 goto error2;
2323 }
2324 CloseHandle(pi.hThread);
2325 DWORD len = script.length(), wlen;
2326 if (!WriteFile(pfd[1], script.c_str(), len, &wlen, NULL) || wlen < len)
2327 std::cerr << "Unexpected failure while sending script to shell" << std::endl;
2328 CloseHandle(pfd[0]);
2329 CloseHandle(pfd[1]);
2330 ++running_jobs;
2331 job_pids[pi.hProcess] = job_id;
2332 return Running;
2333#else
2334 int pfd[2];
2335 if (false)
2336 {
2337 error2:
2338 close(pfd[0]);
2339 close(pfd[1]);
2340 goto error;
2341 }
2342 if (pipe(pfd) == -1)
2343 goto error;
2344 if (setenv("REMAKE_JOB_ID", job_id_.c_str(), 1))
2345 goto error2;
2346 if (pid_t pid = vfork())
2347 {
2348 if (pid == -1) goto error2;
2349 ssize_t len = script.length();
2350 if (write(pfd[1], script.c_str(), len) < len)
2351 std::cerr << "Unexpected failure while sending script to shell" << std::endl;
2352 close(pfd[0]);
2353 close(pfd[1]);
2354 ++running_jobs;
2355 job_pids[pid] = job_id;
2356 return Running;
2357 }
2358 // Child process starts here. Notice the use of vfork above.
2359 char const *argv[5] = { "sh", "-e", "-s", NULL, NULL };
2360 if (echo_scripts) argv[3] = "-v";
2361 close(pfd[1]);
2362 if (pfd[0] != 0)
2363 {
2364 dup2(pfd[0], 0);
2365 close(pfd[0]);
2366 }
2368 execve("/bin/sh", (char **)argv, environ);
2370#endif
2371}
static std::string prepare_script(job_t const &job)
Definition remake.cpp:2175
char ** environ
static bool echo_scripts
Definition remake.cpp:726

Referenced by complete_request(), and start().

◆ server_loop()

static void server_loop ( )
static

Loop until all the jobs have finished.

Postcondition
There are no client requests left, not even virtual ones.

Definition at line 2825 of file remake.cpp.

2826{
2827 while (handle_clients())
2828 {
2829 DEBUG_open << "Handling events... ";
2830 #ifdef WINDOWS
2831 size_t len = job_pids.size() + 1;
2832 HANDLE h[len];
2833 int num = 0;
2834 for (pid_job_map::const_iterator i = job_pids.begin(),
2835 i_end = job_pids.end(); i != i_end; ++i, ++num)
2836 {
2837 h[num] = i->first;
2838 }
2840 h[num] = aev;
2845 if (len <= w)
2846 continue;
2847 if (w == len - 1)
2848 {
2849 accept_client();
2850 continue;
2851 }
2852 pid_t pid = h[w];
2853 DWORD s = 0;
2854 bool res = GetExitCodeProcess(pid, &s) && s == 0;
2857 #else
2860 fd_set fdset;
2861 FD_ZERO(&fdset);
2863 int ret = pselect(socket_fd + 1, &fdset, NULL, NULL, NULL, &emptymask);
2864 if (ret > 0 /* && FD_ISSET(socket_fd, &fdset)*/) accept_client();
2865 if (!got_SIGCHLD) continue;
2866 got_SIGCHLD = 0;
2867 pid_t pid;
2868 int status;
2869 while ((pid = waitpid(-1, &status, WNOHANG)) > 0)
2870 {
2871 bool res = WIFEXITED(status) && WEXITSTATUS(status) == 0;
2873 }
2874 #endif
2875 }
2876
2877 assert(clients.empty());
2878}
static void accept_client()
Definition remake.cpp:2691
static bool handle_clients()
Definition remake.cpp:2495
static void finalize_job(pid_t pid, bool res)
Definition remake.cpp:2810
static volatile sig_atomic_t got_SIGCHLD
Definition remake.cpp:761

Referenced by server_mode().

◆ server_mode()

static void server_mode ( std::string const & remakefile,
string_list const & targets )
static

Load dependencies and rules, listen to client requests, and loop until all the requests have completed. If Remakefile is obsolete, perform a first run with it only, then reload the rules, and perform a second with the original clients.

Definition at line 2886 of file remake.cpp.

2887{
2890 create_server();
2892 {
2893 clients.push_back(client_t());
2894 clients.back().pending.push_back(remakefile);
2895 server_loop();
2896 if (build_failure) goto early_exit;
2897 variables.clear();
2898 specific_rules.clear();
2899 generic_rules.clear();
2900 first_target.clear();
2902 }
2903 clients.push_back(client_t());
2904 if (!targets.empty()) clients.back().pending = targets;
2905 else if (!first_target.empty())
2906 clients.back().pending.push_back(first_target);
2907 server_loop();
2908 early_exit:
2910#ifndef WINDOWS
2913#endif
2916 {
2917 std::cout << "remake: Leaving directory `" << prefix_dir << '\'' << std::endl;
2918 }
2920}
static void save_dependencies()
Definition remake.cpp:1489
static void load_dependencies()
Definition remake.cpp:1473
static void load_rules(std::string const &remakefile)
Definition remake.cpp:1777
static void create_server()
Definition remake.cpp:2611
static void server_loop()
Definition remake.cpp:2825
static std::string first_target
Definition remake.cpp:716
static rule_list generic_rules
Definition remake.cpp:634
static variable_map variables
Definition remake.cpp:619
static bool changed_prefix_dir
Definition remake.cpp:746
static rule_map specific_rules
Definition remake.cpp:639
static std::string prefix_dir
Definition remake.cpp:741

Referenced by main().

◆ start()

static status_e start ( std::string const & target,
client_list::iterator & current )
static

Create a job for target according to the loaded rules. Mark all the targets from the rule as running and reset their dependencies. Inherit variables from current, if enabled. If the rule has dependencies, create a new client to build them just before current, and change current so that it points to it.

Definition at line 2380 of file remake.cpp.

2381{
2382 int job_id = job_counter++;
2383 DEBUG_open << "Starting job " << job_id << " for " << target << "... ";
2384 job_t &job = jobs[job_id];
2386 if (job.rule.targets.empty())
2387 {
2388 status[target].status = Failed;
2389 DEBUG_close << "failed\n";
2390 std::cerr << "No rule for building " << target << std::endl;
2391 return Failed;
2392 }
2393 bool has_deps = !job.rule.deps.empty() || !job.rule.wdeps.empty();
2395 if (has_deps && status[target].status == Recheck)
2397 for (string_list::const_iterator i = job.rule.targets.begin(),
2398 i_end = job.rule.targets.end(); i != i_end; ++i)
2399 {
2400 status[*i].status = st;
2401 }
2402 if (propagate_vars) job.vars = current->vars;
2403 for (assign_map::const_iterator i = job.rule.assigns.begin(),
2404 i_end = job.rule.assigns.end(); i != i_end; ++i)
2405 {
2406 std::pair<variable_map::iterator, bool> k =
2407 job.vars.insert(std::make_pair(i->first, string_list()));
2408 string_list &v = k.first->second;
2409 if (i->second.append)
2410 {
2411 if (k.second)
2412 {
2413 variable_map::const_iterator j = variables.find(i->first);
2414 if (j != variables.end()) v = j->second;
2415 }
2416 }
2417 else if (!k.second) v.clear();
2418 v.insert(v.end(), i->second.value.begin(), i->second.value.end());
2419 }
2420 if (has_deps)
2421 {
2422 current = clients.insert(current, client_t());
2423 current->job_id = job_id;
2424 current->pending = job.rule.deps;
2425 current->pending.insert(current->pending.end(),
2426 job.rule.wdeps.begin(), job.rule.wdeps.end());
2427 if (propagate_vars) current->vars = job.vars;
2428 current->delayed = true;
2429 return RunningRecheck;
2430 }
2431 return run_script(job_id, job);
2432}
static void find_rule(job_t &job, std::string const &target)
Definition remake.cpp:1932
static int job_counter
Definition remake.cpp:694

Referenced by handle_clients().