00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032 #if defined(__linux__)
00033
00034 # include <stdint.h>
00035
00036 # include <sys/sysinfo.h>
00037 # include <unistd.h>
00038 #endif
00039
00040 #include <stdlib.h>
00041 #include <signal.h>
00042 #include <Basics.H>
00043 #include <OS.H>
00044 #include <FdStream.H>
00045 #include <VestaConfig.H>
00046 #include <TCP_sock.H>
00047 #include <SRPC.H>
00048 #include <VestaSource.H>
00049 #include <UniqueId.H>
00050
00051 #include <sys/utsname.h>
00052 #include <sys/sysinfo.h>
00053 #if defined(__digital__)
00054 # include <machine/hal_sysinfo.h>
00055 #endif
00056
00057 #include <sstream>
00058
00059 #include "RunToolClient.H"
00060 #include "RunToolDaemon.H"
00061 #include "Launcher.h"
00062
00063 extern "C" {
00064 #include "get_load.h"
00065 }
00066
00067 using std::ios;
00068 using std::ifstream;
00069 using std::istringstream;
00070 using std::cout;
00071 using std::cin;
00072 using std::cerr;
00073 using std::endl;
00074 using FS::OFdStream;
00075
00076
00077
00078 const Text DEVNULL("/dev/null");
00079 const int UNUSED = SYSERROR;
00080
00081
00082
00083 static void close_fd(fd_t &fd) throw ();
00084
00085
00086
00087
00088 class std_info {
00089 public:
00090 sockaddr_in sock;
00091 TCP_sock *s;
00092 fd_t f;
00093
00094 std_info() throw ();
00095 ~std_info() throw ();
00096 };
00097
00098 std_info::std_info() throw ()
00099 {
00100 s = NULL;
00101 f = NO_FD;
00102 }
00103
00104 std_info::~std_info() throw ()
00105 {
00106 if (s == NULL) close_fd(f);
00107 else delete s;
00108 }
00109
00110 typedef Sequence<Basics::cond*> CondSeq;
00111
00112
00113
00114
00115
00116
00117
00118
00119
00120
00121
00122
00123
00124
00125 class children {
00126 public:
00127 static void init(int running, int pending) throw ();
00128
00129
00130
00131
00132
00133 static bool my_turn() throw();
00134
00135
00136
00137
00138
00139
00140 static int wait_for(pid_t pid, SRPC *client, bool &killed)
00141 throw ();
00142
00143
00144
00145
00146
00147 static void killer_body() throw ();
00148
00149
00150
00151 static void call_failed() throw ();
00152
00153
00154
00155
00156
00157
00158 private:
00159
00160 class child_info {
00161 public:
00162 pid_t pid;
00163 SRPC *client;
00164 bool killed;
00165
00166 child_info() throw ()
00167 { this->pid = UNUSED; this->client = NULL;
00168 this->killed = false; }
00169 };
00170
00171
00172 static Basics::mutex mu;
00173 static int maxChildren;
00174 static int maxPending;
00175 static child_info *info;
00176 static int nInUse;
00177 static int nPending;
00178 static Basics::thread killer;
00179
00180 static CondSeq pending;
00181
00182
00183
00184 friend void Info(SRPC *srpc, int intfVersion, int procId) throw(SRPC::failure);
00185 };
00186
00187
00188
00189
00190 class req_data {
00191 public:
00192
00193 Text stdin_file;
00194 std_info out;
00195 std_info err;
00196 sockaddr_in fsroot_sock;
00197 LongId fsroot_fh;
00198 Text wd;
00199 chars_seq ev;
00200 chars_seq argv;
00201
00202
00203 fd_t stdin_fd;
00204 Text chroot_to;
00205 fd_t error_pipe[2];
00206
00207
00208
00209
00210
00211
00212 req_data() throw ();
00213 ~req_data() throw ();
00214 };
00215
00216 req_data::req_data() throw ()
00217 {
00218
00219
00220 stdin_fd = NO_FD;
00221 error_pipe[0] = NO_FD;
00222 error_pipe[1] = NO_FD;
00223 }
00224
00225 req_data::~req_data() throw ()
00226 {
00227 close_fd(stdin_fd);
00228 close_fd(error_pipe[0]);
00229 close_fd(error_pipe[1]);
00230 }
00231
00232
00233
00234
00235 Basics::mutex children::mu;
00236 int children::maxChildren;
00237 int children::maxPending;
00238 int children::nInUse;
00239 int children::nPending;
00240 children::child_info *children::info;
00241 Basics::thread children::killer;
00242 CondSeq children::pending;
00243
00244
00245 static Text helper;
00246 static chars_seq helper_switches;
00247 static fd_t trouble_fd;
00248 static bool debug_mode = false;
00249 static Text volatile_root;
00250 static Text sysname, release, version, machine;
00251 static FP::Tag uniqueid;
00252 static unsigned int cpus, cpuMHz, memKB;
00253 static int sync_after_tool = 1;
00254
00255
00256
00257 struct call_failure { int code; Text msg; };
00258
00259 static void call_failed(int c, const Text &m) throw (call_failure)
00260 {
00261 call_failure f;
00262 f.code = c;
00263 f.msg = m;
00264 throw(f);
00265 }
00266
00267 static void fail_with_errno(const Text &m, int e = 0) throw (call_failure)
00268 {
00269 if (e == 0) e = errno;
00270 Text emsg = Basics::errno_Text(e);
00271 call_failed(implementation_error, m + " (" + emsg + ")");
00272 }
00273
00274 static void PrintMsgWithErrno(const Text &msg) throw ()
00275 {
00276 int saved_errno = errno;
00277 cerr << "\n*** Error: " << msg;
00278 cerr << "("
00279 << Basics::errno_Text(saved_errno)
00280 << ")" << endl;
00281 cerr << "*** Continuing..." << endl;
00282 }
00283
00284 static Text config_lookup(const Text &key) throw (call_failure)
00285 {
00286 try {
00287 Text val(VestaConfig::get_Text(RUN_TOOL_CONFIG_SECTION, key));
00288 return val;
00289 } catch (VestaConfig::failure f) {
00290 call_failed(implementation_error, f.msg);
00291 }
00292 return "";
00293 }
00294
00295 static void close_fd(fd_t &fd) throw()
00296 {
00297 if (fd == NO_FD) return;
00298 close(fd);
00299 fd = NO_FD;
00300 }
00301
00302 static void move_fd(fd_t from_fd, fd_t to_fd) throw ()
00303
00304
00305 {
00306 dup2(from_fd, to_fd);
00307 close_fd(from_fd);
00308 }
00309
00310
00311
00312 static void setup_stdin( req_data &d) throw (call_failure)
00313
00314
00315 {
00316 const Text f(d.stdin_file.Empty() ? DEVNULL : d.stdin_file);
00317 d.stdin_fd = open(f.cchars(), O_RDONLY, 0);
00318 if (d.stdin_fd < 0) fail_with_errno("Can't open stdin file " + f);
00319 }
00320
00321 static void setup_std_info( std_info &i)
00322 throw (call_failure, TCP_sock::failure)
00323
00324 {
00325 if (i.sock.sin_addr.s_addr == 0 && i.sock.sin_port == 0) {
00326 i.s = NULL;
00327 i.f = open(DEVNULL.cchars(), O_WRONLY, 0);
00328 if (i.f == SYSERROR) {
00329 fail_with_errno("Can't open " + DEVNULL + " for std{out,err}");
00330 }
00331 } else {
00332
00333 i.s = NEW(TCP_sock);
00334 i.s->connect_to(i.sock);
00335 i.f = i.s->get_fd();
00336 }
00337 }
00338
00339
00340
00341
00342 static void simulate_child_failure(fd_t error_wr, fd_t fallback_wr,
00343 int r,
00344 const char *msg,
00345 int e = 0)
00346 throw ()
00347 {
00348
00349
00350 if (e == 0) e = errno;
00351 Text emsg = Basics::errno_Text(e);
00352
00353
00354
00355 if((write(error_wr, msg, strlen(msg)) == SYSERROR) ||
00356 (write(error_wr, " (", 2) == SYSERROR) ||
00357 (write(error_wr, emsg.cchars(), emsg.Length()) == SYSERROR) ||
00358 (write(error_wr, ")\n", 2) == SYSERROR) ||
00359 ((fsync(error_wr) == SYSERROR) &&
00360
00361
00362 (errno != EINVAL)))
00363 {
00364
00365
00366
00367 write(fallback_wr, msg, strlen(msg));
00368 write(fallback_wr, " (", 2);
00369 write(fallback_wr, emsg.cchars(), emsg.Length());
00370 write(fallback_wr, ")\n", 2);
00371 fsync(fallback_wr);
00372 }
00373
00374
00375
00376
00377 _exit(r);
00378 }
00379
00380
00381
00382 static void *children_killer_body(void *arg) throw ()
00383
00384 {
00385 children::killer_body();
00386 return (void *)NULL;
00387 }
00388
00389 void children::init(int running, int pending) throw ()
00390 {
00391 children::nInUse = 0;
00392 children::nPending = 0;
00393 children::maxChildren = running;
00394 children::maxPending = pending;
00395 children::info = NEW_ARRAY(child_info, running);
00396 children::killer.fork_and_detach(children_killer_body, NULL);
00397 }
00398
00399 bool children::my_turn() throw()
00400 {
00401 bool result;
00402
00403 children::mu.lock();
00404
00405
00406 int nRunning =
00407
00408 children::nInUse +
00409
00410
00411 (children::nPending - children::pending.size());
00412 assert(children::nPending >= children::pending.size());
00413 assert(nRunning >= 0);
00414
00415
00416 if(nRunning < children::maxChildren)
00417 {
00418
00419
00420 assert(children::pending.size() == 0);
00421
00422
00423 assert(children::nInUse < children::maxChildren);
00424 children::nInUse++;
00425 result = true;
00426 }
00427
00428 else if(children::pending.size() < children::maxPending)
00429 {
00430
00431 children::nPending++;
00432
00433
00434 assert(nRunning > 0);
00435
00436
00437
00438 Basics::cond c;
00439 children::pending.addhi(&c);
00440 c.wait(children::mu);
00441
00442
00443
00444 assert(children::nInUse < children::maxChildren);
00445 children::nPending--;
00446 children::nInUse++;
00447 result = true;
00448 }
00449
00450 else
00451 {
00452 result = false;
00453 }
00454
00455 children::mu.unlock();
00456
00457 return result;
00458 }
00459
00460 int children::wait_for(pid_t pid, SRPC *client, bool &killed) throw ()
00461
00462
00463
00464
00465
00466
00467 {
00468 int status;
00469 int slot = -1;
00470
00471 children::mu.lock();
00472
00473 for(int i = 0; (i < children::maxChildren) && (slot < 0); i++)
00474 {
00475 if(children::info[i].pid == UNUSED)
00476 {
00477 slot = i;
00478 }
00479 }
00480 assert(slot >= 0);
00481
00482
00483 assert(info[slot].pid == UNUSED);
00484 children::info[slot].pid = pid;
00485 children::info[slot].client = client;
00486
00487
00488
00489 children::mu.unlock();
00490
00491
00492 pid_t done_pid = waitpid(pid, &status, 0);
00493
00494 if(done_pid == SYSERROR)
00495 {
00496 int l_errno = errno;
00497 cerr << "waitpid(pid = " << pid << ") returned an error: "
00498 << strerror(l_errno) << " (" << l_errno << ")"
00499 << endl;
00500 }
00501
00502 assert(done_pid == pid);
00503
00504
00505
00506 children::mu.lock();
00507
00508
00509 killed = children::info[slot].killed;
00510 children::info[slot].pid = UNUSED;
00511 children::nInUse--;
00512 children::info[slot].client = NULL;
00513 children::info[slot].killed = false;
00514
00515
00516
00517 if(children::pending.size() > 0)
00518 {
00519 Basics::cond *c = children::pending.remlo();
00520 assert(c != 0);
00521 c->signal();
00522 }
00523 assert(children::nPending >= children::pending.size());
00524
00525 children::mu.unlock();
00526 return status;
00527 }
00528
00529 void children::killer_body() throw ()
00530
00531
00532
00533
00534
00535
00536 {
00537 while (true) {
00538
00539 Basics::thread::pause(30);
00540
00541
00542 children::mu.lock();
00543 for (int i = 0; i < children::maxChildren; i++) {
00544 child_info *slot = children::info + i;
00545 if (slot->pid != UNUSED && slot->client != NULL) {
00546
00547 if (!slot->client->alive()) {
00548
00549 int sig = (slot->killed) ? SIGKILL : SIGTERM;
00550 if (kill(-slot->pid, sig) != 0) {
00551
00552
00553
00554
00555
00556 } else {
00557 slot->killed = true;
00558 }
00559 }
00560 }
00561 }
00562 children::mu.unlock();
00563 }
00564 }
00565
00566 void children::call_failed() throw ()
00567 {
00568
00569
00570 children::mu.lock();
00571 children::nInUse--;
00572
00573
00574
00575 if(children::pending.size() > 0)
00576 {
00577 Basics::cond *c = children::pending.remlo();
00578 assert(c != 0);
00579 c->signal();
00580 }
00581 assert(children::nPending >= children::pending.size());
00582
00583
00584 children::mu.unlock();
00585 }
00586
00587
00588
00589 static void RunTool(SRPC *srpc, int intfVersion) throw(SRPC::failure)
00590 {
00591
00592 bool in_use_slot = false;
00593
00594 try {
00595 req_data d;
00596
00597
00598
00599 srpc->recv_Text( d.stdin_file);
00600 d.out.sock = srpc->recv_socket();
00601 d.err.sock = srpc->recv_socket();
00602 d.fsroot_sock = srpc->recv_socket();
00603 int len = sizeof(d.fsroot_fh);
00604 srpc->recv_bytes_here( (char *)&d.fsroot_fh, len);
00605 if (len != sizeof(d.fsroot_fh)) {
00606 call_failed(implementation_error, "Invalid fsroot");
00607 }
00608 srpc->recv_Text( d.wd);
00609 srpc->recv_chars_seq( d.ev);
00610 srpc->recv_chars_seq( d.argv);
00611 if (d.argv[0] == NULL) {
00612 call_failed(implementation_error, "Null command");
00613 }
00614 srpc->recv_end();
00615
00616
00617 if(!children::my_turn())
00618 {
00619
00620
00621 call_failed(client_error, "request denied: server too busy");
00622 }
00623
00624 in_use_slot = true;
00625
00626
00627
00628 unsigned int index;
00629 (void) d.fsroot_fh.getParent(&index);
00630 char arc[(sizeof(index) * 2) + 1];
00631 sprintf(arc, "%08x", index);
00632 d.chroot_to = volatile_root + PathnameSep + arc;
00633
00634
00635 setup_stdin( d);
00636 setup_std_info( d.out);
00637 setup_std_info( d.err);
00638
00639
00640 if (getenv("STOP_BEFORE_TOOL")) {
00641 cerr << "Stop before tool; root = " << d.chroot_to << endl;
00642 cerr << "Hit enter to continue: ";
00643 char enter;
00644 cin.get(enter);
00645 }
00646
00647
00648 if (pipe(d.error_pipe) == SYSERROR) {
00649 fail_with_errno("pipe call failed!");
00650 }
00651
00652
00653
00654
00655
00656
00657
00658
00659
00660
00661
00662 Text wd(d.chroot_to + PathnameSep + d.wd);
00663
00664
00665 Text chdir_emsg("Can't establish working directory " + wd);
00666
00667
00668
00669
00670
00671
00672
00673
00674
00675
00676
00677
00678
00679
00680
00681
00682
00683
00684 char **helper_cmd =
00685 NEW_ARRAY(char *,
00686 1+
00687 helper_switches.length()+
00688 2+
00689 2+
00690 1+d.ev.length()+
00691 1+d.argv.length()+
00692 1);
00693 int i = 0;
00694 helper_cmd[i++] = helper.chars();
00695 int j;
00696 for (j = 0; j < helper_switches.length(); ) {
00697 helper_cmd[i++] = helper_switches[j++];
00698 }
00699 helper_cmd[i++] = "-err";
00700 char error_wr[20];
00701 sprintf(error_wr, "%d", d.error_pipe[1]);
00702 helper_cmd[i++] = error_wr;
00703 helper_cmd[i++] = "-root";
00704 helper_cmd[i++] = d.chroot_to.chars();
00705 helper_cmd[i++] = "-env";
00706 for (j = 0; j < d.ev.length(); ) {
00707 helper_cmd[i++] = d.ev[j++];
00708 }
00709 helper_cmd[i++] = "-cmd";
00710 for (j = 0; j < d.argv.length(); ) {
00711 helper_cmd[i++] = d.argv[j++];
00712 }
00713 helper_cmd[i++] = NULL;
00714
00715
00716
00717 pid_t child_pid = fork();
00718 switch (child_pid) {
00719 case -1:
00720 fail_with_errno("Couldn't fork process to execute command");
00721 break;
00722
00723
00724 case 0:
00725
00726 ::setpgid(0, 0);
00727
00728
00729 close_fd(d.error_pipe[0]);
00730
00731
00732 move_fd(d.stdin_fd, STDIN_FILENO);
00733 move_fd(d.out.f, STDOUT_FILENO);
00734 move_fd(d.err.f, STDERR_FILENO);
00735
00736
00737
00738 if (chdir(wd.chars()) == SYSERROR) {
00739 simulate_child_failure(d.error_pipe[1], trouble_fd,
00740 implementation_error,
00741 chdir_emsg.cchars());
00742 }
00743
00744
00745 execv(helper_cmd[0], helper_cmd);
00746
00747
00748 simulate_child_failure(d.error_pipe[1], trouble_fd,
00749 configuration_error,
00750 "Can't exec helper");
00751
00752
00753 _exit(implementation_error);
00754
00755
00756 break;
00757
00758
00759 default:
00760
00761 if (debug_mode) {
00762 OFdStream os(trouble_fd);
00763 os << "\n*** Launching child process " << child_pid
00764 << " ***" << endl;
00765 }
00766
00767
00768 close_fd(d.error_pipe[1]);
00769
00770
00771 bool child_killed;
00772 int s = children::wait_for(child_pid, srpc, child_killed);
00773
00774 in_use_slot = false;
00775
00776
00777 if (debug_mode) {
00778 if (child_killed) {
00779 cerr << "*** Child process " << child_pid
00780 << " killed due to client termination ***" << endl;
00781 } else {
00782 cerr << "*** Finished child process " << child_pid
00783 << ": exit status " << WEXITSTATUS(s)
00784 << ", signal " << WTERMSIG(s) << " ***" << endl;
00785 }
00786 }
00787
00788
00789 if (getenv("STOP_AFTER_TOOL")) {
00790 cerr << "Stop after tool; root = " << d.chroot_to << endl;
00791 cerr << "Hit enter to continue: ";
00792 char enter;
00793 cin.get(enter);
00794 } else if (WIFSIGNALED(s) && getenv("STOP_AFTER_TOOL_SIGNALED")) {
00795 cerr << "Stop after tool signaled " << WTERMSIG(s)
00796 << "; root = " << d.chroot_to << endl;
00797 cerr << "Hit enter to continue: ";
00798 char enter;
00799 cin.get(enter);
00800 } else if (WIFEXITED(s) && WEXITSTATUS(s) &&
00801 getenv("STOP_AFTER_TOOL_ERROR")) {
00802 cerr << "Stop after tool error " << WEXITSTATUS(s)
00803 << "; root = " << d.chroot_to << endl;
00804 cerr << "Hit enter to continue: ";
00805 char enter;
00806 cin.get(enter);
00807 }
00808
00809
00810 Text msg("");
00811 while (true) {
00812 char buf[100];
00813 int ct = read(d.error_pipe[0], buf, sizeof(buf)-1);
00814 if (ct == 0) break;
00815 if (ct == SYSERROR)
00816 fail_with_errno("Can't read from error_pipe!");
00817 buf[ct] = 0;
00818 msg += buf;
00819 }
00820 close_fd(d.error_pipe[0]);
00821
00822
00823 if (!msg.Empty()) {
00824
00825
00826 int r;
00827 switch (WEXITSTATUS(s)) {
00828 case unrecognized_switch:
00829 case chroot_failure:
00830 case wd_not_in_root:
00831 r = configuration_error;
00832 break;
00833 case execve_failure:
00834 r = client_error;
00835 break;
00836 default:
00837 r = implementation_error;
00838 break;
00839 }
00840 call_failed(r, msg);
00841
00842 }
00843
00844
00845
00846 int i = sync_after_tool;
00847 while (i--) {
00848
00849
00850
00851
00852
00853
00854
00855
00856
00857
00858
00859
00860
00861
00862
00863 ::sync();
00864 }
00865
00866
00867 srpc->send_int(WIFEXITED(s) ? WEXITSTATUS(s) : 0);
00868 srpc->send_int(WIFSIGNALED(s) ? WTERMSIG(s) : 0);
00869 if(intfVersion >= RUN_TOOL_CORE_VERSION) {
00870 srpc->send_bool(WCOREDUMP(s) ? true : false);
00871 }
00872 srpc->send_end();
00873 break;
00874 }
00875
00876
00877 delete [] helper_cmd;
00878 helper_cmd = NULL;
00879 }
00880 catch(const TCP_sock::failure &tf) {
00881
00882 if(in_use_slot)
00883 {
00884 children::call_failed();
00885 }
00886
00887 srpc->send_failure(implementation_error, "TCP failure: " + tf.msg);
00888 }
00889 catch(const call_failure &cf) {
00890
00891 if(in_use_slot)
00892 {
00893 children::call_failed();
00894 }
00895
00896 srpc->send_failure(cf.code, cf.msg);
00897 }
00898 catch (SRPC::failure) {
00899
00900
00901
00902 if(in_use_slot)
00903 {
00904 children::call_failed();
00905 }
00906
00907 throw;
00908 }
00909
00910
00911
00912 assert(!in_use_slot);
00913 }
00914
00915 void Info(SRPC *srpc, int intfVersion, int procId) throw(SRPC::failure)
00916 {
00917 float load = GetLoadPoint();
00918 children::mu.lock();
00919 int max_tools = children::maxChildren;
00920 int cur_tools, cur_pending, max_pending;
00921 if(intfVersion >= RUN_TOOL_LOAD_VERSION) {
00922 cur_tools = children::nInUse;
00923 cur_pending = children::nPending;
00924 max_pending = children::maxPending;
00925 } else {
00926 cur_tools = children::nInUse + children::nPending;
00927 }
00928 children::mu.unlock();
00929
00930 try {
00931
00932
00933
00934 srpc->recv_end();
00935
00936
00937 srpc->send_Text(sysname);
00938 srpc->send_Text(release);
00939 srpc->send_Text(version);
00940 srpc->send_Text(machine);
00941 srpc->send_int(cpus);
00942 srpc->send_int(cpuMHz);
00943 srpc->send_int(memKB);
00944 srpc->send_int(max_tools);
00945 srpc->send_int(cur_tools);
00946 if (intfVersion >= RUN_TOOL_LOAD_VERSION) {
00947 srpc->send_float(load);
00948 srpc->send_int(cur_pending);
00949 srpc->send_int(max_pending);
00950 }
00951 if (procId != RUN_TOOL_OLDINFO) uniqueid.Send(*srpc);
00952 srpc->send_end();
00953
00954 }
00955 catch(const TCP_sock::failure &tf) {
00956 srpc->send_failure(implementation_error, "TCP failure: " + tf.msg);
00957 }
00958 }
00959
00960 void
00961 RunToolServer(SRPC *srpc, int intfVersion, int procId, void *arg)
00962 throw(SRPC::failure)
00963
00964
00965
00966 {
00967
00968 if(intfVersion > RUN_TOOL_INTERFACE_VERSION) {
00969 srpc->send_failure(SRPC::version_skew,
00970 "RunToolServer: Unsupported interface version");
00971 return;
00972 }
00973
00974
00975 switch (procId) {
00976 case RUN_TOOL_DOIT:
00977 case SRPC::default_proc_id:
00978 RunTool(srpc, intfVersion);
00979 break;
00980
00981 case RUN_TOOL_OLDINFO:
00982 case RUN_TOOL_INFO:
00983 Info(srpc, intfVersion, procId);
00984 break;
00985
00986 default:
00987 srpc->send_failure(SRPC::version_skew, "Unknown proc_id");
00988 break;
00989 }
00990 }
00991
00992 #if defined(__linux__)
00993
00994
00995
00996
00997
00998
00999
01000 static unsigned int get_hw_clock_freq()
01001 {
01002 ifstream pstr("/proc/cpuinfo");
01003
01004 char line[1000];
01005
01006 if(pstr.bad())
01007 {
01008 return 1;
01009 }
01010
01011
01012
01013
01014
01015
01016
01017
01018
01019 for(pstr.getline(line, sizeof(line));
01020 !pstr.eof();
01021 pstr.getline(line, sizeof(line)))
01022 {
01023 const char *l_digits;
01024
01025
01026
01027 if(strncmp(line, "cycle frequency [Hz]", 20) == 0)
01028 {
01029
01030 l_digits = strpbrk(line+20, "0123456789");
01031 if(l_digits != NULL)
01032 {
01033
01034 int freq = atoi(l_digits);
01035 int l_result = (freq + 500000) / 1000000;
01036 return l_result;
01037 }
01038 }
01039
01040
01041 else if(strncmp(line, "cpu MHz", 7) == 0)
01042 {
01043
01044 l_digits = strpbrk(line+7, "0123456789");
01045 if(l_digits != NULL)
01046 {
01047 int l_result = atoi(l_digits);
01048 return l_result;
01049 }
01050 }
01051
01052
01053 else if((strncmp(line, "clock", 5) == 0) && isspace(line[5]))
01054 {
01055
01056 l_digits = strpbrk(line+6, "0123456789");
01057 if(l_digits != NULL)
01058 {
01059 int l_result = atoi(l_digits);
01060 return l_result;
01061 }
01062 }
01063
01064
01065 while(pstr.fail())
01066 {
01067
01068 pstr.clear(pstr.rdstate() & ~ios::failbit);
01069
01070
01071 pstr.getline(line, sizeof(line));
01072 }
01073 }
01074
01075
01076
01077 return 1;
01078 }
01079
01080
01081
01082
01083
01084
01085
01086
01087
01088
01089
01090
01091
01092
01093 static unsigned int get_n_cpus()
01094 {
01095
01096 ifstream l_proc_stat("/proc/stat");
01097
01098
01099 unsigned int l_result = 0;
01100
01101
01102 char l_line[1000];
01103 for(l_proc_stat.getline(l_line, sizeof(l_line));
01104 !l_proc_stat.eof();
01105 l_proc_stat.getline(l_line, sizeof(l_line)))
01106 {
01107
01108 if((strncmp(l_line, "cpu", 3) == 0) && isdigit(l_line[3]))
01109 {
01110 l_result++;
01111 }
01112
01113
01114 while(l_proc_stat.fail())
01115 {
01116
01117 l_proc_stat.clear(l_proc_stat.rdstate() & ~ios::failbit);
01118
01119
01120 l_proc_stat.getline(l_line, sizeof(l_line));
01121 }
01122 }
01123
01124
01125
01126 if(l_result > 0)
01127 {
01128 return l_result;
01129 }
01130
01131
01132 return 1;
01133 }
01134
01135 #endif // defined (__linux__)
01136
01137
01138
01139 void RunToolServerInit(int maxTools, int maxPending) throw(SRPC::failure)
01140 {
01141
01142
01143
01144
01145
01146
01147 try {
01148 if ((trouble_fd = dup(STDERR_FILENO)) == SYSERROR) {
01149 fail_with_errno(
01150 "Can't get file descriptor to report launcher errors");
01151 }
01152 } catch (const call_failure &f) {
01153 cerr << f.msg << endl;
01154 return;
01155 }
01156
01157
01158 static struct utsname u;
01159 uname(&u);
01160 sysname = u.sysname;
01161 release = u.release;
01162 version = u.version;
01163 machine = u.machine;
01164
01165 #if defined(__digital__)
01166
01167 struct cpu_info cpuinfo;
01168 int start = 0;
01169 getsysinfo(GSI_CPU_INFO, (caddr_t) &cpuinfo, sizeof(cpuinfo),
01170 &start, NULL, NULL);
01171 cpus = cpuinfo.cpus_in_box;
01172 cpuMHz = cpuinfo.mhz;
01173 start = 0;
01174 getsysinfo(GSI_PHYSMEM, (caddr_t) &memKB, sizeof(memKB),
01175 &start, NULL, NULL);
01176 #elif defined (__linux__)
01177
01178
01179
01180
01181
01182
01183
01184
01185 cpus = get_n_cpus();
01186 cpuMHz = get_hw_clock_freq();
01187 memKB = ((((unsigned long) sysconf(_SC_PAGE_SIZE)) *
01188 ((unsigned long) sysconf(_SC_PHYS_PAGES)))
01189 / 1024);
01190
01191
01192 assert(cpus > 0);
01193 assert(cpuMHz > 0);
01194 assert(memKB > 0);
01195 #endif
01196
01197
01198
01199 VestaConfig::get(RUN_TOOL_CONFIG_SECTION, "sysname", sysname);
01200 VestaConfig::get(RUN_TOOL_CONFIG_SECTION, "release", release);
01201 VestaConfig::get(RUN_TOOL_CONFIG_SECTION, "version", version);
01202 VestaConfig::get(RUN_TOOL_CONFIG_SECTION, "machine", machine);
01203 try {
01204 cpus = VestaConfig::get_int(RUN_TOOL_CONFIG_SECTION, "cpus");
01205 } catch (VestaConfig::failure) { }
01206 try {
01207 cpuMHz = VestaConfig::get_int(RUN_TOOL_CONFIG_SECTION, "cpuMHz");
01208 } catch (VestaConfig::failure) { }
01209 try {
01210 memKB = VestaConfig::get_int(RUN_TOOL_CONFIG_SECTION, "memKB");
01211 } catch (VestaConfig::failure) { }
01212
01213
01214 uniqueid = UniqueId();
01215
01216
01217 helper = config_lookup("helper");
01218 try {
01219 Text val(VestaConfig::get_Text(RUN_TOOL_CONFIG_SECTION,
01220 "helper_switches"));
01221 istringstream is(val.chars());
01222 char s[100];
01223 while ( is >> s && strlen(s) != 0) {
01224 if (strcmp(s, "-d") == 0) {
01225 int dbgfd;
01226 try {
01227 if ((dbgfd = dup(STDERR_FILENO)) == SYSERROR) {
01228 fail_with_errno(
01229 "Can't get file descriptor for debug output");
01230 }
01231 } catch (call_failure f) {
01232 cerr << f.msg << '\n';
01233 continue;
01234 }
01235 debug_mode = true;
01236 helper_switches += "-dbg";
01237 sprintf(s, "%d", dbgfd);
01238 }
01239 helper_switches += s;
01240 }
01241 } catch(const VestaConfig::failure &f) {
01242
01243 }
01244 try {
01245 sync_after_tool = VestaConfig::get_int(RUN_TOOL_CONFIG_SECTION,
01246 "sync_after_tool");
01247 } catch(const VestaConfig::failure &f) {
01248
01249 }
01250 if (debug_mode) {
01251 cout << "helper command = " << helper;
01252 for (int i = 0; i < helper_switches.length(); i++) {
01253 cout << " " << helper_switches[i];
01254 }
01255 cout << endl;
01256 }
01257
01258 volatile_root = config_lookup("VolatileRootName");
01259
01260 struct stat st;
01261 if (stat(volatile_root.cchars(), &st) < 0) {
01262 cerr << "Can't access volatile root (not mounted?): "
01263 << volatile_root + ": " << strerror(errno) << endl;
01264 exit(1);
01265 }
01266
01267 children::init(maxTools, maxPending);
01268 }
01269
01270 void RunToolServerCleanup() throw ()
01271 {
01272
01273 }