Remake
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
Functions
Server

Functions

static void complete_job (int job_id, bool success)
 
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

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

Referenced by server_loop().

2596 {
2597  DEBUG_open << "Handling client request... ";
2598 
2599  // Accept connection.
2600 #ifdef WINDOWS
2601  socket_t fd = accept(socket_fd, NULL, NULL);
2602  if (fd == INVALID_SOCKET) return;
2603  if (!SetHandleInformation((HANDLE)fd, HANDLE_FLAG_INHERIT, 0))
2604  {
2605  error2:
2606  std::cerr << "Unexpected failure while setting connection with client" << std::endl;
2607  closesocket(fd);
2608  return;
2609  }
2610  // WSAEventSelect puts sockets into nonblocking mode, so disable it here.
2611  u_long nbio = 0;
2612  if (ioctlsocket(fd, FIONBIO, &nbio)) goto error2;
2613 #elif defined(LINUX)
2614  int fd = accept4(socket_fd, NULL, NULL, SOCK_CLOEXEC);
2615  if (fd < 0) return;
2616 #else
2617  int fd = accept(socket_fd, NULL, NULL);
2618  if (fd < 0) return;
2619  if (fcntl(fd, F_SETFD, FD_CLOEXEC) < 0) return;
2620 #endif
2621  clients.push_front(client_t());
2622  client_list::iterator proc = clients.begin();
2623 
2624  if (false)
2625  {
2626  error:
2627  DEBUG_close << "failed\n";
2628  std::cerr << "Received an ill-formed client message" << std::endl;
2629  #ifdef WINDOWS
2630  closesocket(fd);
2631  #else
2632  close(fd);
2633  #endif
2634  clients.erase(proc);
2635  return;
2636  }
2637 
2638  // Receive message. Stop when encountering two nuls in a row.
2639  std::vector<char> buf;
2640  size_t len = 0;
2641  while (len < sizeof(int) + 2 || buf[len - 1] || buf[len - 2])
2642  {
2643  buf.resize(len + 1024);
2644  ssize_t l = recv(fd, &buf[0] + len, 1024, 0);
2645  if (l <= 0) goto error;
2646  len += l;
2647  }
2648 
2649  // Parse job that spawned the client.
2650  int job_id;
2651  memcpy(&job_id, &buf[0], sizeof(int));
2652  proc->socket = fd;
2653  proc->job_id = job_id;
2654  job_map::const_iterator i = jobs.find(job_id);
2655  if (i == jobs.end()) goto error;
2656  DEBUG << "receiving request from job " << job_id << std::endl;
2657  if (propagate_vars) proc->vars = i->second.vars;
2658 
2659  // Parse the targets and the variable assignments.
2660  // Mark the targets as dependencies of the job targets.
2661  dependency_t &dep = *dependencies[i->second.rule.targets.front()];
2662  string_list *last_var = NULL;
2663  char const *p = &buf[0] + sizeof(int);
2664  while (true)
2665  {
2666  len = strlen(p);
2667  if (len == 0)
2668  {
2669  ++waiting_jobs;
2670  break;
2671  }
2672  switch (*p)
2673  {
2674  case 'T':
2675  {
2676  if (len == 1) goto error;
2677  std::string target(p + 1, p + len);
2678  DEBUG << "adding dependency " << target << " to job\n";
2679  proc->pending.push_back(target);
2680  dep.deps.insert(target);
2681  break;
2682  }
2683  case 'V':
2684  {
2685  if (len == 1) goto error;
2686  std::string var(p + 1, p + len);
2687  DEBUG << "adding variable " << var << " to job\n";
2688  last_var = &proc->vars[var];
2689  last_var->clear();
2690  break;
2691  }
2692  case 'W':
2693  {
2694  if (!last_var) goto error;
2695  last_var->push_back(std::string(p + 1, p + len));
2696  break;
2697  }
2698  default:
2699  goto error;
2700  }
2701  p += len + 1;
2702  }
2703 
2704  if (!propagate_vars && !proc->vars.empty())
2705  {
2706  std::cerr << "Assignments are ignored unless 'variable-propagation' is enabled" << std::endl;
2707  proc->vars.clear();
2708  }
2709 }
#define DEBUG_open
Definition: remake.cpp:794
static job_map jobs
Definition: remake.cpp:627
static bool propagate_vars
Definition: remake.cpp:734
std::list< std::string > string_list
Definition: remake.cpp:455
static int waiting_jobs
Definition: remake.cpp:671
static client_list clients
Definition: remake.cpp:638
string_set deps
Definition: remake.cpp:498
int socket_t
Definition: remake.cpp:446
#define DEBUG
Definition: remake.cpp:793
#define DEBUG_close
Definition: remake.cpp:795
static socket_t socket_fd
Definition: remake.cpp:682
static dependency_map dependencies
Definition: remake.cpp:607
static void complete_job ( int  job_id,
bool  success 
)
static

Handle job completion.

Definition at line 2052 of file remake.cpp.

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

2053 {
2054  DEBUG << "Completing job " << job_id << '\n';
2055  job_map::iterator i = jobs.find(job_id);
2056  assert(i != jobs.end());
2057  string_list const &targets = i->second.rule.targets;
2058  if (success)
2059  {
2060  if (show_targets) std::cout << "Finished";
2061  for (string_list::const_iterator j = targets.begin(),
2062  j_end = targets.end(); j != j_end; ++j)
2063  {
2064  update_status(*j);
2065  if (show_targets) std::cout << ' ' << *j;
2066  }
2067  if (show_targets) std::cout << std::endl;
2068  }
2069  else
2070  {
2071  std::cerr << "Failed to build";
2072  for (string_list::const_iterator j = targets.begin(),
2073  j_end = targets.end(); j != j_end; ++j)
2074  {
2075  status[*j].status = Failed;
2076  std::cerr << ' ' << *j;
2077  remove(j->c_str());
2078  }
2079  std::cerr << std::endl;
2080  }
2081  jobs.erase(i);
2082 }
static job_map jobs
Definition: remake.cpp:627
std::list< std::string > string_list
Definition: remake.cpp:455
static status_map status
Definition: remake.cpp:612
static void update_status(std::string const &target)
Definition: remake.cpp:1985
static bool show_targets
Definition: remake.cpp:704
Build failed for target.
Definition: remake.cpp:515
#define DEBUG
Definition: remake.cpp:793
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 2345 of file remake.cpp.

Referenced by handle_clients().

2346 {
2347  DEBUG_open << "Completing request from client of job " << client.job_id << "... ";
2348  if (client.delayed)
2349  {
2350  assert(client.socket == INVALID_SOCKET);
2351  if (success)
2352  {
2353  job_map::const_iterator i = jobs.find(client.job_id);
2354  assert(i != jobs.end());
2355  if (still_need_rebuild(i->second.rule.targets.front()))
2356  run_script(client.job_id, i->second);
2357  else complete_job(client.job_id, true);
2358  }
2359  else complete_job(client.job_id, false);
2360  }
2361  else if (client.socket != INVALID_SOCKET)
2362  {
2363  char res = success ? 1 : 0;
2364  send(client.socket, &res, 1, MSG_NOSIGNAL);
2365  #ifdef WINDOWS
2366  closesocket(client.socket);
2367  #else
2368  close(client.socket);
2369  #endif
2370  --waiting_jobs;
2371  }
2372 
2373  if (client.job_id < 0 && !success) build_failure = true;
2374 }
static bool still_need_rebuild(std::string const &target)
Definition: remake.cpp:2018
int job_id
Job for which the built script called remake and spawned the client (negative for original clients)...
Definition: remake.cpp:587
static status_e run_script(int job_id, job_t const &job)
Definition: remake.cpp:2170
#define DEBUG_open
Definition: remake.cpp:794
static job_map jobs
Definition: remake.cpp:627
bool delayed
Whether it is a dependency client and a script has to be started on request completion.
Definition: remake.cpp:592
static int waiting_jobs
Definition: remake.cpp:671
static bool build_failure
Definition: remake.cpp:687
socket_t socket
Socket used to reply to the client (invalid for pseudo clients).
Definition: remake.cpp:586
static void complete_job(int job_id, bool success)
Definition: remake.cpp:2052
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 2515 of file remake.cpp.

Referenced by server_mode().

2516 {
2517  if (false)
2518  {
2519  error:
2520  perror("Failed to create server");
2521 #ifndef WINDOWS
2522  error2:
2523 #endif
2524  exit(EXIT_FAILURE);
2525  }
2526  DEBUG_open << "Creating server... ";
2527 
2528 #ifdef WINDOWS
2529  // Prepare a windows socket.
2530  struct sockaddr_in socket_addr;
2531  socket_addr.sin_family = AF_INET;
2532  socket_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
2533  socket_addr.sin_port = 0;
2534 
2535  // Create and listen to the socket.
2536  socket_fd = socket(AF_INET, SOCK_STREAM, 0);
2537  if (socket_fd == INVALID_SOCKET) goto error;
2538  if (!SetHandleInformation((HANDLE)socket_fd, HANDLE_FLAG_INHERIT, 0))
2539  goto error;
2540  if (bind(socket_fd, (struct sockaddr *)&socket_addr, sizeof(sockaddr_in)))
2541  goto error;
2542  int len = sizeof(sockaddr_in);
2543  if (getsockname(socket_fd, (struct sockaddr *)&socket_addr, &len))
2544  goto error;
2545  std::ostringstream buf;
2546  buf << socket_addr.sin_port;
2547  if (!SetEnvironmentVariable("REMAKE_SOCKET", buf.str().c_str()))
2548  goto error;
2549  if (listen(socket_fd, 1000)) goto error;
2550 #else
2551  // Set signal handlers for SIGCHLD and SIGINT.
2552  // Block SIGCHLD (unblocked during select).
2553  sigset_t sigmask;
2554  sigemptyset(&sigmask);
2555  sigaddset(&sigmask, SIGCHLD);
2556  if (sigprocmask(SIG_BLOCK, &sigmask, NULL) == -1) goto error;
2557  struct sigaction sa;
2558  sa.sa_flags = 0;
2559  sigemptyset(&sa.sa_mask);
2560  sa.sa_handler = &sigchld_handler;
2561  if (sigaction(SIGCHLD, &sa, NULL) == -1) goto error;
2562  sa.sa_handler = &sigint_handler;
2563  if (sigaction(SIGINT, &sa, NULL) == -1) goto error;
2564 
2565  // Prepare a named unix socket in temporary directory.
2566  socket_name = tempnam(NULL, "rmk-");
2567  if (!socket_name) goto error2;
2568  struct sockaddr_un socket_addr;
2569  size_t len = strlen(socket_name);
2570  if (len >= sizeof(socket_addr.sun_path) - 1) goto error2;
2571  socket_addr.sun_family = AF_UNIX;
2572  strcpy(socket_addr.sun_path, socket_name);
2573  len += sizeof(socket_addr.sun_family);
2574  if (setenv("REMAKE_SOCKET", socket_name, 1)) goto error;
2575 
2576  // Create and listen to the socket.
2577 #ifdef LINUX
2578  socket_fd = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0);
2579  if (socket_fd == INVALID_SOCKET) goto error;
2580 #else
2581  socket_fd = socket(AF_UNIX, SOCK_STREAM, 0);
2582  if (socket_fd == INVALID_SOCKET) goto error;
2583  if (fcntl(socket_fd, F_SETFD, FD_CLOEXEC) < 0) goto error;
2584 #endif
2585  if (bind(socket_fd, (struct sockaddr *)&socket_addr, len))
2586  goto error;
2587  if (listen(socket_fd, 1000)) goto error;
2588 #endif
2589 }
#define DEBUG_open
Definition: remake.cpp:794
static char * socket_name
Definition: remake.cpp:693
static void sigint_handler(int)
Definition: remake.cpp:744
static socket_t socket_fd
Definition: remake.cpp:682
static void sigchld_handler(int)
Definition: remake.cpp:739
static void finalize_job ( pid_t  pid,
bool  res 
)
static

Handle child process exit status.

Definition at line 2714 of file remake.cpp.

Referenced by server_loop().

2715 {
2716  pid_job_map::iterator i = job_pids.find(pid);
2717  assert(i != job_pids.end());
2718  int job_id = i->second;
2719  job_pids.erase(i);
2720  --running_jobs;
2721  complete_job(job_id, res);
2722 }
static pid_job_map job_pids
Definition: remake.cpp:632
static int running_jobs
Definition: remake.cpp:663
static void complete_job(int job_id, bool success)
Definition: remake.cpp:2052
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 no free slots left is fine.

Definition at line 2402 of file remake.cpp.

Referenced by server_loop().

2403 {
2404  DEBUG_open << "Handling client requests... ";
2405  restart:
2406  bool need_restart = false;
2407 
2408  for (client_list::iterator i = clients.begin(), i_next = i,
2409  i_end = clients.end(); i != i_end && has_free_slots(); i = i_next)
2410  {
2411  ++i_next;
2412  DEBUG_open << "Handling client from job " << i->job_id << "... ";
2413 
2414  // Remove running targets that have finished.
2415  for (string_set::iterator j = i->running.begin(), j_next = j,
2416  j_end = i->running.end(); j != j_end; j = j_next)
2417  {
2418  ++j_next;
2419  status_map::const_iterator k = status.find(*j);
2420  assert(k != status.end());
2421  switch (k->second.status)
2422  {
2423  case Running:
2424  break;
2425  case Failed:
2426  i->failed = true;
2427  if (!keep_going) goto complete;
2428  // no break
2429  case Uptodate:
2430  case Remade:
2431  i->running.erase(j);
2432  break;
2433  case Recheck:
2434  case Todo:
2435  assert(false);
2436  }
2437  }
2438 
2439  // Start pending targets.
2440  while (!i->pending.empty())
2441  {
2442  std::string target = i->pending.front();
2443  i->pending.pop_front();
2444  switch (get_status(target).status)
2445  {
2446  case Running:
2447  i->running.insert(target);
2448  break;
2449  case Failed:
2450  pending_failed:
2451  i->failed = true;
2452  if (!keep_going) goto complete;
2453  // no break
2454  case Uptodate:
2455  case Remade:
2456  break;
2457  case Recheck:
2458  case Todo:
2459  client_list::iterator j = i;
2460  switch (start(target, i))
2461  {
2462  case Failed:
2463  goto pending_failed;
2464  case Running:
2465  // A shell was started, check for free slots.
2466  j->running.insert(target);
2467  if (!has_free_slots()) return true;
2468  break;
2469  case Recheck:
2470  // Switch to the dependency client that was inserted.
2471  j->running.insert(target);
2472  i_next = j;
2473  break;
2474  case Remade:
2475  // Nothing to run.
2476  need_restart = true;
2477  break;
2478  default:
2479  assert(false);
2480  }
2481  }
2482  }
2483 
2484  // Try to complete the request.
2485  // (This might start a new job if it was a dependency client.)
2486  if (i->running.empty() || i->failed)
2487  {
2488  complete:
2489  complete_request(*i, !i->failed);
2490  DEBUG_close << (i->failed ? "failed\n" : "finished\n");
2491  clients.erase(i);
2492  need_restart = true;
2493  }
2494  }
2495 
2496  if (running_jobs != waiting_jobs) return true;
2497  if (running_jobs == 0 && clients.empty()) return false;
2498  if (need_restart) goto restart;
2499 
2500  // There is a circular dependency.
2501  // Try to break it by completing one of the requests.
2502  assert(!clients.empty());
2503  std::cerr << "Circular dependency detected" << std::endl;
2504  client_list::iterator i = clients.begin();
2505  complete_request(*i, false);
2506  clients.erase(i);
2507  goto restart;
2508 }
static void complete_request(client_t &client, bool success)
Definition: remake.cpp:2345
#define DEBUG_open
Definition: remake.cpp:794
Target is being rebuilt.
Definition: remake.cpp:513
static int waiting_jobs
Definition: remake.cpp:671
Target is up-to-date.
Definition: remake.cpp:510
static status_t const & get_status(std::string const &target)
Definition: remake.cpp:1915
static client_list clients
Definition: remake.cpp:638
static bool keep_going
Definition: remake.cpp:650
static status_map status
Definition: remake.cpp:612
static int running_jobs
Definition: remake.cpp:663
Target is missing or obsolete.
Definition: remake.cpp:511
Build failed for target.
Definition: remake.cpp:515
static bool has_free_slots()
Definition: remake.cpp:2379
Target has an obsolete dependency.
Definition: remake.cpp:512
Target was successfully rebuilt.
Definition: remake.cpp:514
#define DEBUG_close
Definition: remake.cpp:795
static status_e start(std::string const &target, client_list::iterator &current)
Definition: remake.cpp:2291
static bool has_free_slots ( )
static

Return whether there are slots for starting new jobs.

Definition at line 2379 of file remake.cpp.

Referenced by handle_clients().

2380 {
2381  if (max_active_jobs <= 0) return true;
2383 }
static int max_active_jobs
Definition: remake.cpp:644
static int waiting_jobs
Definition: remake.cpp:671
static int running_jobs
Definition: remake.cpp:663
static std::string prepare_script ( job_t const &  job)
static

Return the script obtained by substituting variables.

Definition at line 2087 of file remake.cpp.

Referenced by run_script().

2088 {
2089  std::string const &s = job.rule.script;
2090  std::istringstream in(s);
2091  std::ostringstream out;
2092  size_t len = s.size();
2093 
2094  while (!in.eof())
2095  {
2096  size_t pos = in.tellg(), p = s.find('$', pos);
2097  if (p == std::string::npos || p == len - 1) p = len;
2098  out.write(&s[pos], p - pos);
2099  if (p == len) break;
2100  ++p;
2101  switch (s[p])
2102  {
2103  case '$':
2104  out << '$';
2105  in.seekg(p + 1);
2106  break;
2107  case '<':
2108  if (!job.rule.deps.empty())
2109  out << job.rule.deps.front();
2110  in.seekg(p + 1);
2111  break;
2112  case '^':
2113  {
2114  bool first = true;
2115  for (string_list::const_iterator i = job.rule.deps.begin(),
2116  i_end = job.rule.deps.end(); i != i_end; ++i)
2117  {
2118  if (first) first = false;
2119  else out << ' ';
2120  out << *i;
2121  }
2122  in.seekg(p + 1);
2123  break;
2124  }
2125  case '@':
2126  assert(!job.rule.targets.empty());
2127  out << job.rule.targets.front();
2128  in.seekg(p + 1);
2129  break;
2130  case '*':
2131  out << job.stem;
2132  in.seekg(p + 1);
2133  break;
2134  case '(':
2135  {
2136  in.seekg(p - 1);
2137  bool first = true;
2138  input_generator gen(in, &job.vars, true);
2139  while (true)
2140  {
2141  std::string w;
2142  input_status s = gen.next(w);
2143  if (s == SyntaxError)
2144  {
2145  // TODO
2146  return "false";
2147  }
2148  if (s == Eof) break;
2149  if (first) first = false;
2150  else out << ' ';
2151  out << w;
2152  }
2153  break;
2154  }
2155  default:
2156  // Let dollars followed by an unrecognized character
2157  // go through. This differs from Make, which would
2158  // use a one-letter variable.
2159  out << '$';
2160  in.seekg(p);
2161  }
2162  }
2163 
2164  return out.str();
2165 }
Definition: remake.cpp:1154
input_status
Definition: remake.cpp:1150
static status_e run_script ( int  job_id,
job_t const &  job 
)
static

Execute the script from rule.

Definition at line 2170 of file remake.cpp.

Referenced by complete_request(), and start().

2171 {
2173  dep->targets = job.rule.targets;
2174  dep->deps.insert(job.rule.deps.begin(), job.rule.deps.end());
2175  if (show_targets) std::cout << "Building";
2176  for (string_list::const_iterator i = job.rule.targets.begin(),
2177  i_end = job.rule.targets.end(); i != i_end; ++i)
2178  {
2179  dependencies[*i] = dep;
2180  if (show_targets) std::cout << ' ' << *i;
2181  }
2182  if (show_targets) std::cout << std::endl;
2183 
2184  std::string script = prepare_script(job);
2185 
2186  std::ostringstream job_id_buf;
2187  job_id_buf << job_id;
2188  std::string job_id_ = job_id_buf.str();
2189 
2190  DEBUG_open << "Starting script for job " << job_id << "... ";
2191  if (script.empty())
2192  {
2193  DEBUG_close << "no script\n";
2194  complete_job(job_id, true);
2195  return Remade;
2196  }
2197 
2198  if (false)
2199  {
2200  error:
2201  DEBUG_close << "failed\n";
2202  complete_job(job_id, false);
2203  return Failed;
2204  }
2205 
2206 #ifdef WINDOWS
2207  HANDLE pfd[2];
2208  if (false)
2209  {
2210  error2:
2211  CloseHandle(pfd[0]);
2212  CloseHandle(pfd[1]);
2213  goto error;
2214  }
2215  if (!CreatePipe(&pfd[0], &pfd[1], NULL, 0))
2216  goto error;
2217  if (!SetHandleInformation(pfd[0], HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT))
2218  goto error2;
2219  STARTUPINFO si;
2220  ZeroMemory(&si, sizeof(STARTUPINFO));
2221  si.cb = sizeof(STARTUPINFO);
2222  si.hStdError = GetStdHandle(STD_ERROR_HANDLE);
2223  si.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
2224  si.hStdInput = pfd[0];
2225  si.dwFlags |= STARTF_USESTDHANDLES;
2226  PROCESS_INFORMATION pi;
2227  ZeroMemory(&pi, sizeof(PROCESS_INFORMATION));
2228  if (!SetEnvironmentVariable("REMAKE_JOB_ID", job_id_.c_str()))
2229  goto error2;
2230  char const *argv = echo_scripts ? "SH.EXE -e -s -v" : "SH.EXE -e -s";
2231  if (!CreateProcess(NULL, (char *)argv, NULL, NULL,
2232  true, 0, NULL, NULL, &si, &pi))
2233  {
2234  goto error2;
2235  }
2236  CloseHandle(pi.hThread);
2237  DWORD len = script.length(), wlen;
2238  if (!WriteFile(pfd[1], script.c_str(), len, &wlen, NULL) || wlen < len)
2239  std::cerr << "Unexpected failure while sending script to shell" << std::endl;
2240  CloseHandle(pfd[0]);
2241  CloseHandle(pfd[1]);
2242  ++running_jobs;
2243  job_pids[pi.hProcess] = job_id;
2244  return Running;
2245 #else
2246  int pfd[2];
2247  if (false)
2248  {
2249  error2:
2250  close(pfd[0]);
2251  close(pfd[1]);
2252  goto error;
2253  }
2254  if (pipe(pfd) == -1)
2255  goto error;
2256  if (setenv("REMAKE_JOB_ID", job_id_.c_str(), 1))
2257  goto error2;
2258  if (pid_t pid = vfork())
2259  {
2260  if (pid == -1) goto error2;
2261  ssize_t len = script.length();
2262  if (write(pfd[1], script.c_str(), len) < len)
2263  std::cerr << "Unexpected failure while sending script to shell" << std::endl;
2264  close(pfd[0]);
2265  close(pfd[1]);
2266  ++running_jobs;
2267  job_pids[pid] = job_id;
2268  return Running;
2269  }
2270  // Child process starts here. Notice the use of vfork above.
2271  char const *argv[5] = { "sh", "-e", "-s", NULL, NULL };
2272  if (echo_scripts) argv[3] = "-v";
2273  close(pfd[1]);
2274  if (pfd[0] != 0)
2275  {
2276  dup2(pfd[0], 0);
2277  close(pfd[0]);
2278  }
2279  execve("/bin/sh", (char **)argv, environ);
2280  _exit(EXIT_FAILURE);
2281 #endif
2282 }
#define DEBUG_open
Definition: remake.cpp:794
string_list targets
Definition: remake.cpp:497
Target is being rebuilt.
Definition: remake.cpp:513
string_set deps
Definition: remake.cpp:498
static pid_job_map job_pids
Definition: remake.cpp:632
char ** environ
static bool echo_scripts
Definition: remake.cpp:709
static int running_jobs
Definition: remake.cpp:663
static bool show_targets
Definition: remake.cpp:704
Build failed for target.
Definition: remake.cpp:515
Target was successfully rebuilt.
Definition: remake.cpp:514
#define DEBUG_close
Definition: remake.cpp:795
static void complete_job(int job_id, bool success)
Definition: remake.cpp:2052
static dependency_map dependencies
Definition: remake.cpp:607
static std::string prepare_script(job_t const &job)
Definition: remake.cpp:2087
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 2729 of file remake.cpp.

Referenced by server_mode().

2730 {
2731  while (handle_clients())
2732  {
2733  DEBUG_open << "Handling events... ";
2734  #ifdef WINDOWS
2735  size_t len = job_pids.size() + 1;
2736  HANDLE h[len];
2737  int num = 0;
2738  for (pid_job_map::const_iterator i = job_pids.begin(),
2739  i_end = job_pids.end(); i != i_end; ++i, ++num)
2740  {
2741  h[num] = i->first;
2742  }
2743  WSAEVENT aev = WSACreateEvent();
2744  h[num] = aev;
2745  WSAEventSelect(socket_fd, aev, FD_ACCEPT);
2746  DWORD w = WaitForMultipleObjects(len, h, false, INFINITE);
2747  WSAEventSelect(socket_fd, aev, 0);
2748  WSACloseEvent(aev);
2749  if (len <= w)
2750  continue;
2751  if (w == len - 1)
2752  {
2753  accept_client();
2754  continue;
2755  }
2756  pid_t pid = h[w];
2757  DWORD s = 0;
2758  bool res = GetExitCodeProcess(pid, &s) && s == 0;
2759  CloseHandle(pid);
2760  finalize_job(pid, res);
2761  #else
2762  sigset_t emptymask;
2763  sigemptyset(&emptymask);
2764  fd_set fdset;
2765  FD_ZERO(&fdset);
2766  FD_SET(socket_fd, &fdset);
2767  int ret = pselect(socket_fd + 1, &fdset, NULL, NULL, NULL, &emptymask);
2768  if (ret > 0 /* && FD_ISSET(socket_fd, &fdset)*/) accept_client();
2769  if (!got_SIGCHLD) continue;
2770  got_SIGCHLD = 0;
2771  pid_t pid;
2772  int status;
2773  while ((pid = waitpid(-1, &status, WNOHANG)) > 0)
2774  {
2775  bool res = WIFEXITED(status) && WEXITSTATUS(status) == 0;
2776  finalize_job(pid, res);
2777  }
2778  #endif
2779  }
2780 
2781  assert(clients.empty());
2782 }
#define DEBUG_open
Definition: remake.cpp:794
static client_list clients
Definition: remake.cpp:638
static pid_job_map job_pids
Definition: remake.cpp:632
static status_map status
Definition: remake.cpp:612
static volatile sig_atomic_t got_SIGCHLD
Definition: remake.cpp:737
static bool handle_clients()
Definition: remake.cpp:2402
static void accept_client()
Definition: remake.cpp:2595
static socket_t socket_fd
Definition: remake.cpp:682
static void finalize_job(pid_t pid, bool res)
Definition: remake.cpp:2714
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 2790 of file remake.cpp.

Referenced by main().

2791 {
2793  load_rules(remakefile);
2794  create_server();
2795  if (get_status(remakefile).status != Uptodate)
2796  {
2797  clients.push_back(client_t());
2798  clients.back().pending.push_back(remakefile);
2799  server_loop();
2800  if (build_failure) goto early_exit;
2801  variables.clear();
2802  specific_rules.clear();
2803  generic_rules.clear();
2804  first_target.clear();
2805  load_rules(remakefile);
2806  }
2807  clients.push_back(client_t());
2808  if (!targets.empty()) clients.back().pending = targets;
2809  else if (!first_target.empty())
2810  clients.back().pending.push_back(first_target);
2811  server_loop();
2812  early_exit:
2813  close(socket_fd);
2814 #ifndef WINDOWS
2815  remove(socket_name);
2816  free(socket_name);
2817 #endif
2820  {
2821  std::cout << "remake: Leaving directory `" << prefix_dir << '\'' << std::endl;
2822  }
2823  exit(build_failure ? EXIT_FAILURE : EXIT_SUCCESS);
2824 }
static void create_server()
Definition: remake.cpp:2515
static void save_dependencies()
Definition: remake.cpp:1465
static char * socket_name
Definition: remake.cpp:693
static variable_map variables
Definition: remake.cpp:602
static rule_map specific_rules
Definition: remake.cpp:622
Target is up-to-date.
Definition: remake.cpp:510
static status_t const & get_status(std::string const &target)
Definition: remake.cpp:1915
static std::string first_target
Definition: remake.cpp:699
static void server_loop()
Definition: remake.cpp:2729
static bool build_failure
Definition: remake.cpp:687
static client_list clients
Definition: remake.cpp:638
static status_map status
Definition: remake.cpp:612
static std::string prefix_dir
Definition: remake.cpp:724
static bool show_targets
Definition: remake.cpp:704
static bool changed_prefix_dir
Definition: remake.cpp:729
static socket_t socket_fd
Definition: remake.cpp:682
static void load_dependencies(std::istream &in)
Definition: remake.cpp:1415
static void load_rules(std::string const &remakefile)
Definition: remake.cpp:1713
static rule_list generic_rules
Definition: remake.cpp:617
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 2291 of file remake.cpp.

Referenced by handle_clients().

2292 {
2293  int job_id = job_counter++;
2294  DEBUG_open << "Starting job " << job_id << " for " << target << "... ";
2295  job_t &job = jobs[job_id];
2296  find_rule(job, target);
2297  if (job.rule.targets.empty())
2298  {
2299  status[target].status = Failed;
2300  DEBUG_close << "failed\n";
2301  std::cerr << "No rule for building " << target << std::endl;
2302  return Failed;
2303  }
2304  for (string_list::const_iterator i = job.rule.targets.begin(),
2305  i_end = job.rule.targets.end(); i != i_end; ++i)
2306  {
2307  status[*i].status = Running;
2308  }
2309  if (propagate_vars) job.vars = current->vars;
2310  for (assign_map::const_iterator i = job.rule.assigns.begin(),
2311  i_end = job.rule.assigns.end(); i != i_end; ++i)
2312  {
2313  std::pair<variable_map::iterator, bool> k =
2314  job.vars.insert(std::make_pair(i->first, string_list()));
2315  string_list &v = k.first->second;
2316  if (i->second.append)
2317  {
2318  if (k.second)
2319  {
2320  variable_map::const_iterator j = variables.find(i->first);
2321  if (j != variables.end()) v = j->second;
2322  }
2323  }
2324  else if (!k.second) v.clear();
2325  v.insert(v.end(), i->second.value.begin(), i->second.value.end());
2326  }
2327  if (!job.rule.deps.empty() || !job.rule.wdeps.empty())
2328  {
2329  current = clients.insert(current, client_t());
2330  current->job_id = job_id;
2331  current->pending = job.rule.deps;
2332  current->pending.insert(current->pending.end(),
2333  job.rule.wdeps.begin(), job.rule.wdeps.end());
2334  if (propagate_vars) current->vars = job.vars;
2335  current->delayed = true;
2336  return Recheck;
2337  }
2338  return run_script(job_id, job);
2339 }
static status_e run_script(int job_id, job_t const &job)
Definition: remake.cpp:2170
static void find_rule(job_t &job, std::string const &target)
Definition: remake.cpp:1858
#define DEBUG_open
Definition: remake.cpp:794
static job_map jobs
Definition: remake.cpp:627
static bool propagate_vars
Definition: remake.cpp:734
static variable_map variables
Definition: remake.cpp:602
std::list< std::string > string_list
Definition: remake.cpp:455
Target is being rebuilt.
Definition: remake.cpp:513
string_list wdeps
Like deps, except that they are not registered as dependencies.
Definition: remake.cpp:547
static client_list clients
Definition: remake.cpp:638
string_list deps
Dependencies used for an implicit call to remake at the start of the script.
Definition: remake.cpp:546
assign_map assigns
Assignment of variables.
Definition: remake.cpp:548
static status_map status
Definition: remake.cpp:612
variable_map vars
Values of local variables.
Definition: remake.cpp:564
Build failed for target.
Definition: remake.cpp:515
string_list targets
Files produced by this rule.
Definition: remake.cpp:545
Target has an obsolete dependency.
Definition: remake.cpp:512
#define DEBUG_close
Definition: remake.cpp:795
rule_t rule
Original rule.
Definition: remake.cpp:562
static int job_counter
Definition: remake.cpp:677