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 2689 of file remake.cpp.

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

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 2131 of file remake.cpp.

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

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 2436 of file remake.cpp.

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

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 2609 of file remake.cpp.

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

Referenced by server_mode().

◆ finalize_job()

static void finalize_job ( pid_t pid,
bool res )
static

Handle child process exit status.

Definition at line 2808 of file remake.cpp.

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

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 2493 of file remake.cpp.

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

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 2470 of file remake.cpp.

2471{
2472 if (max_active_jobs <= 0) return true;
2474}
static int max_active_jobs
Definition remake.cpp:659

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 2173 of file remake.cpp.

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

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 2256 of file remake.cpp.

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

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 2823 of file remake.cpp.

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

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 2884 of file remake.cpp.

2885{
2889 create_server();
2891 {
2892 clients.push_back(client_t());
2893 clients.back().pending.push_back(remakefile);
2894 server_loop();
2895 if (build_failure) goto early_exit;
2897 specific_rules.clear();
2898 generic_rules.clear();
2899 first_target.clear();
2901 }
2902 clients.push_back(client_t());
2903 if (!targets.empty()) clients.back().pending = targets;
2904 else if (!first_target.empty())
2905 clients.back().pending.push_back(first_target);
2906 server_loop();
2907 early_exit:
2909#ifndef WINDOWS
2912#endif
2915 {
2916 std::cout << "remake: Leaving directory `" << prefix_dir << '\'' << std::endl;
2917 }
2919}
static void save_dependencies()
Definition remake.cpp:1487
static void load_dependencies()
Definition remake.cpp:1471
static void load_rules(std::string const &remakefile)
Definition remake.cpp:1775
static void create_server()
Definition remake.cpp:2609
static void server_loop()
Definition remake.cpp:2823
static std::string first_target
Definition remake.cpp:714
static rule_list generic_rules
Definition remake.cpp:632
static variable_map variables
Definition remake.cpp:617
static bool changed_prefix_dir
Definition remake.cpp:744
std::map< std::string, string_list > variable_map
Definition remake.cpp:517
static rule_map specific_rules
Definition remake.cpp:637
static std::string prefix_dir
Definition remake.cpp:739

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 2378 of file remake.cpp.

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

Referenced by handle_clients().