VmApps: wrapperWeir.cpp

File wrapperWeir.cpp, 21.8 KB (added by dgquintas, 15 years ago)

actual code extracted from the rtf

Line 
1// This file is part of BOINC.
2// http://boinc.berkeley.edu
3// Copyright (C) 2008 University of California
4//
5// BOINC is free software; you can redistribute it and/or modify it
6// under the terms of the GNU Lesser General Public License
7// as published by the Free Software Foundation,
8// either version 3 of the License, or (at your option) any later version.
9//
10// BOINC is distributed in the hope that it will be useful,
11// but WITHOUT ANY WARRANTY; without even the implied warranty of
12// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13// See the GNU Lesser General Public License for more details.
14//
15// You should have received a copy of the GNU Lesser General Public
16// License
17// along with BOINC.  If not, see <http://www.gnu.org/licenses/>.
18
19// vmwrapper.C
20// VMWare wrapper program - lets you use BOINC to drive a VMWare Server
21// guest OS
22
23#include <stdio.h>
24#include <vector>
25#include <string>
26#ifdef _WIN32
27#include "boinc_win.h"
28#include "win_util.h"
29#else
30#include <sys/wait.h>
31#include <sys/types.h>
32#include <sys/stat.h>
33#include <unistd.h>
34#include "procinfo.h"
35#endif
36
37#include "boinc_api.h"
38#include "diagnostics.h"
39#include "filesys.h"
40#include "parse.h"
41#include "str_util.h"
42#include "util.h"
43#include "error_numbers.h"
44
45#include "vmware-vix/vix.h"
46
47#define JOB_FILENAME "job.xml"
48#define CHECKPOINT_FILENAME "checkpoint.txt"
49
50#define POLL_PERIOD 1.0
51
52using std::vector;
53using std::string;
54
55struct TASK
56{
57        string application;
58        string stdin_filename;
59        string stdout_filename;
60        string stderr_filename;
61
62        string vm;
63        string innerjob;
64        string datadir;
65        string partial_credit;
66        string snapshots;
67        string user;
68        string password;
69
70        vector < string > data;
71        vector < string > output;
72
73        string checkpoint_filename;
74        // name of task's checkpoint file, if any
75        double checkpoint_cpu_time;
76        // CPU time at last checkpoint
77        string command_line;
78        double weight;
79        // contribution of this task to overall fraction done
80        double final_cpu_time;
81        double starting_cpu;
82        // how much CPU time was used by tasks before this in the job file
83        bool    suspended;
84        double wall_cpu_time;
85        // for estimating CPU time on Win98/ME and Mac
86
87
88        #ifdef _WIN32
89
90        HANDLE pid_handle;
91        DWORD pid;
92        HANDLE thread_handle;
93        struct _stat last_stat;                          // mod time of checkpoint file
94
95        #else
96
97        int pid;
98        struct stat last_stat;
99
100        #endif
101
102
103        bool stat_first;
104        int parse (XML_PARSER &);
105        bool poll (int &status);
106        int run (int argc, char **argv);
107        void kill ();
108        void stop ();
109        void resume ();
110        double cpu_time ();
111
112        inline bool has_checkpointed ()
113        {
114                bool changed = false;
115
116                if (checkpoint_filename.size () == 0)
117                        return false;
118
119                struct stat new_stat;
120
121                int retval = stat (checkpoint_filename.c_str (), &new_stat);
122
123                if (retval)
124                        return false;
125
126                if (!stat_first && new_stat.st_mtime != last_stat.st_mtime)
127                {
128                        changed = true;
129                }
130
131                stat_first = false;
132
133                last_stat.st_mtime = new_stat.st_mtime;
134                return changed;
135        }
136};
137
138vector < TASK > tasks;
139APP_INIT_DATA aid;
140bool graphics = false;
141
142int TASK::parse (XML_PARSER & xp)
143{
144
145        string this_data, this_output;
146        char tag[1024], buf[8192], buf2[8192];
147
148        bool is_tag;
149
150        weight = 1;
151        final_cpu_time = 0;
152        stat_first = true;
153        while (!xp.get (tag, sizeof (tag), is_tag))
154        {
155                if (!is_tag)
156                {
157                        fprintf (stderr, "SCHED_CONFIG::parse(): unexpected text %s\n",
158                                tag);
159                        continue;
160                }
161                if (!strcmp (tag, "/task"))
162                {
163                        return 0;
164                }
165                else if (xp.parse_string (tag, "application", application))
166                        continue;
167
168                else if (xp.parse_string (tag, "innerjob", innerjob))
169                        continue;
170                else if (xp.parse_string (tag, "vm", vm))
171                        continue;
172                else if (xp.parse_string (tag, "datadir", datadir))
173                        continue;
174                else if (xp.parse_string (tag, "partial_credit", partial_credit))
175                        continue;
176                else if (xp.parse_string (tag, "snapshots", snapshots))
177                        continue;
178
179
180                else if (xp.parse_string (tag, "data", this_data)) {
181                        data.push_back(this_data);
182                        continue;
183                }
184
185                else if (xp.parse_string (tag, "output", this_output)) {
186                        output.push_back(this_output);
187                        continue;
188                }
189
190                else if (xp.parse_string (tag, "user", user))
191                        continue;
192                else if (xp.parse_string (tag, "password", password))
193                        continue;
194
195                else if (xp.parse_string (tag, "stdin_filename", stdin_filename))
196                        continue;
197                else if (xp.parse_string (tag, "stdout_filename", stdout_filename))
198                        continue;
199                else if (xp.parse_string (tag, "stderr_filename", stderr_filename))
200                        continue;
201                else if (xp.parse_str (tag, "command_line", buf, sizeof (buf)))
202                {
203                        while (1)
204                        {
205                                char *p = strstr (buf, "$PROJECT_DIR");
206
207                                if (!p)
208                                        break;
209                                strcpy (buf2, p + strlen ("$PROJECT_DIR"));
210                                strcpy (p, aid.project_dir);
211                                strcat (p, buf2);
212                        }
213                        command_line = buf;
214                        continue;
215                }
216                else if (xp.
217                        parse_string (tag, "checkpoint_filename",
218                        checkpoint_filename))
219                        continue;
220                else if (xp.parse_double (tag, "weight", weight))
221                        continue;
222        }
223        return ERR_XML_PARSE;
224}
225
226
227int parse_job_file ()
228{
229        MIOFILE mf;
230        char tag[1024], buf[256];
231
232        bool is_tag;
233
234        boinc_resolve_filename (JOB_FILENAME, buf, 1024);
235        FILE *f = boinc_fopen (buf, "r");
236
237        if (!f)
238        {
239                fprintf (stderr, "can't open job file %s\n", buf);
240                return ERR_FOPEN;
241        }
242        mf.init_file (f);
243        XML_PARSER xp (&mf);
244
245        if (!xp.parse_start ("job_desc"))
246                return ERR_XML_PARSE;
247        while (!xp.get (tag, sizeof (tag), is_tag))
248        {
249                if (!is_tag)
250                {
251                        fprintf (stderr, "SCHED_CONFIG::parse(): unexpected text %s\n",
252                                tag);
253                        continue;
254                }
255                if (!strcmp (tag, "/job_desc"))
256                {
257                        fclose (f);
258                        return 0;
259                }
260                if (!strcmp (tag, "task"))
261                {
262                        TASK task;
263                        int retval = task.parse (xp);
264
265                        if (!retval)
266                        {
267                                tasks.push_back (task);
268                        }
269                }
270        }
271        fclose (f);
272        return ERR_XML_PARSE;
273}
274
275
276#ifdef _WIN32
277// CreateProcess() takes HANDLEs for the stdin/stdout.
278// We need to use CreateFile() to get them.  Ugh.
279//
280HANDLE
281win_fopen (const char *path, const char *mode)
282{
283        SECURITY_ATTRIBUTES sa;
284        memset (&sa, 0, sizeof (sa));
285        sa.nLength = sizeof (sa);
286        sa.bInheritHandle = TRUE;
287
288        if (!strcmp (mode, "r"))
289        {
290                return CreateFile (path,
291                        GENERIC_READ,
292                        FILE_SHARE_READ, &sa, OPEN_EXISTING, 0, 0);
293        }
294        else if (!strcmp (mode, "w"))
295        {
296                return CreateFile (path,
297                        GENERIC_WRITE,
298                        FILE_SHARE_WRITE, &sa, OPEN_ALWAYS, 0, 0);
299        }
300        else if (!strcmp (mode, "a"))
301        {
302                HANDLE
303                        hAppend = CreateFile (path,
304                        GENERIC_WRITE,
305                        FILE_SHARE_WRITE, &sa, OPEN_ALWAYS, 0, 0);
306                SetFilePointer (hAppend, 0, NULL, FILE_END);
307                return hAppend;
308        }
309        else
310        {
311                return 0;
312        }
313}
314#endif
315
316void slash_to_backslash (char *p)
317{
318        while (1)
319        {
320                char *q = strchr (p, '/');
321
322                if (!q)
323                        break;
324                *q = '\\';
325        }
326}
327
328
329int TASK::run (int argct, char **argvt)
330{
331        string stdout_path, stdin_path, stderr_path;
332        char app_path[1024], buf[256];
333
334        strcpy (buf, application.c_str ());
335        char *p = strstr (buf, "$PROJECT_DIR");
336
337        if (p)
338        {
339                p += strlen ("$PROJECT_DIR");
340                sprintf (app_path, "%s%s", aid.project_dir, p);
341        }
342        else
343        {
344                boinc_resolve_filename (buf, app_path, sizeof (app_path));
345        }
346
347        // Append wrapper's command-line arguments to those in the job file.
348        //
349        for (int i = 1; i < argct; i++)
350        {
351                command_line += argvt[i];
352                if ((i + 1) < argct)
353                {
354                        command_line += string (" ");
355                }
356        }
357
358        fprintf (stderr, "wrapper: running %s (%s)\n",
359                app_path, command_line.c_str ());
360
361        #ifdef _WIN32
362        PROCESS_INFORMATION process_info;
363        STARTUPINFO startup_info;
364        string command;
365
366        slash_to_backslash (app_path);
367        memset (&process_info, 0, sizeof (process_info));
368        memset (&startup_info, 0, sizeof (startup_info));
369        command = string ("\"") + app_path + string ("\" ") + command_line;
370
371        // pass std handles to app
372        //
373        startup_info.dwFlags = STARTF_USESTDHANDLES;
374        if (stdout_filename != "")
375        {
376                boinc_resolve_filename_s (stdout_filename.c_str (), stdout_path);
377                startup_info.hStdOutput = win_fopen (stdout_path.c_str (), "a");
378        }
379        if (stdin_filename != "")
380        {
381                boinc_resolve_filename_s (stdin_filename.c_str (), stdin_path);
382                startup_info.hStdInput = win_fopen (stdin_path.c_str (), "r");
383        }
384        if (stderr_filename != "")
385        {
386                boinc_resolve_filename_s (stderr_filename.c_str (), stderr_path);
387                startup_info.hStdError = win_fopen (stderr_path.c_str (), "a");
388        }
389        else
390        {
391                startup_info.hStdError = win_fopen (STDERR_FILE, "a");
392        }
393
394                                                                 // bInheritHandles
395        if (!CreateProcess (app_path, (LPSTR) command.c_str (), NULL, NULL, TRUE,
396                CREATE_NO_WINDOW | IDLE_PRIORITY_CLASS,
397                NULL, NULL, &startup_info, &process_info))
398        {
399                return ERR_EXEC;
400        }
401        pid_handle = process_info.hProcess;
402        pid = process_info.dwProcessId;
403        thread_handle = process_info.hThread;
404        SetThreadPriority (thread_handle, THREAD_PRIORITY_IDLE);
405        #else
406        int retval, argc;
407        char progname[256];
408        char *argv[256];
409        char arglist[4096];
410        FILE *stdout_file;
411        FILE *stdin_file;
412        FILE *stderr_file;
413
414        pid = fork ();
415        if (pid == -1)
416        {
417                boinc_finish (ERR_FORK);
418        }
419        if (pid == 0)
420        {
421                // we're in the child process here
422                //
423                // open stdout, stdin if file names are given
424                // NOTE: if the application is restartable,
425                // we should deal with atomicity somehow
426                //
427                if (stdout_filename != "")
428                {
429                        boinc_resolve_filename_s (stdout_filename.c_str (), stdout_path);
430                        stdout_file = freopen (stdout_path.c_str (), "a", stdout);
431                        if (!stdout_file)
432                                return ERR_FOPEN;
433                }
434                if (stdin_filename != "")
435                {
436                        boinc_resolve_filename_s (stdin_filename.c_str (), stdin_path);
437                        stdin_file = freopen (stdin_path.c_str (), "r", stdin);
438                        if (!stdin_file)
439                                return ERR_FOPEN;
440                }
441                if (stderr_filename != "")
442                {
443                        boinc_resolve_filename_s (stderr_filename.c_str (), stderr_path);
444                        stderr_file = freopen (stderr_path.c_str (), "a", stderr);
445                        if (!stderr_file)
446                                return ERR_FOPEN;
447                }
448                // construct argv
449                // TODO: use malloc instead of stack var
450                //
451                argv[0] = app_path;
452                strlcpy (arglist, command_line.c_str (), sizeof (arglist));
453                argc = parse_command_line (arglist, argv + 1);
454                setpriority (PRIO_PROCESS, 0, PROCESS_IDLE_PRIORITY);
455                retval = execv (app_path, argv);
456                exit (ERR_EXEC);
457        }
458        #endif
459        wall_cpu_time = 0;
460        suspended = false;
461        return 0;
462}
463
464
465bool TASK::poll (int &status)
466{
467        if (!suspended)
468                wall_cpu_time += POLL_PERIOD;
469        #ifdef _WIN32
470        unsigned long
471                exit_code;
472
473        if (GetExitCodeProcess (pid_handle, &exit_code))
474        {
475                if (exit_code != STILL_ACTIVE)
476                {
477                        status = exit_code;
478                        final_cpu_time = cpu_time ();
479                        return true;
480                }
481        }
482        #else
483        int
484                wpid,
485                stat;
486        struct rusage
487                ru;
488
489        wpid = wait4 (pid, &status, WNOHANG, &ru);
490        if (wpid)
491        {
492                final_cpu_time =
493                        (float) ru.ru_utime.tv_sec + ((float) ru.ru_utime.tv_usec) / 1e+6;
494                return true;
495        }
496        #endif
497        return false;
498}
499
500
501void TASK::kill ()
502{
503        #ifdef _WIN32
504        TerminateProcess (pid_handle, -1);
505        #else
506        ::kill (pid, SIGKILL);
507        #endif
508}
509
510
511void TASK::stop ()
512{
513        suspended = true;
514}
515
516
517void TASK::resume ()
518{
519        suspended = false;
520}
521
522
523
524
525double TASK::cpu_time ()
526{
527        #ifdef _WIN32
528        FILETIME creation_time, exit_time, kernel_time, user_time;
529        ULARGE_INTEGER tKernel, tUser;
530        LONGLONG totTime;
531
532        int retval = GetProcessTimes (pid_handle, &creation_time, &exit_time,
533                &kernel_time,
534                &user_time);
535
536        if (retval == 0)
537        {
538                return wall_cpu_time;
539        }
540
541        tKernel.LowPart = kernel_time.dwLowDateTime;
542        tKernel.HighPart = kernel_time.dwHighDateTime;
543        tUser.LowPart = user_time.dwLowDateTime;
544        tUser.HighPart = user_time.dwHighDateTime;
545        totTime = tKernel.QuadPart + tUser.QuadPart;
546
547        return totTime / 1.e7;
548        #elif defined(__APPLE__)
549        // There's no easy way to get another process's CPU time in Mac OS X
550        //
551        return wall_cpu_time;
552        #else
553        return linux_cpu_time (pid);
554        #endif
555}
556
557
558
559
560// Support for multiple tasks.
561// We keep a checkpoint file that says how many tasks we've completed
562// and how much CPU time has been used so far
563//
564void write_checkpoint (int ntasks, double cpu)
565{
566        FILE *f = fopen (CHECKPOINT_FILENAME, "w");
567
568        if (!f)
569                return;
570        fprintf (f, "%d %f\n", ntasks, cpu);
571        fclose (f);
572}
573
574
575void read_checkpoint (int &ntasks, double &cpu)
576{
577        int nt;
578        double c;
579
580        ntasks = 0;
581        cpu = 0;
582        FILE *f = fopen (CHECKPOINT_FILENAME, "r");
583
584        if (!f)
585                return;
586        int n = fscanf (f, "%d %lf", &nt, &c);
587
588        fclose (f);
589        if (n != 2)
590                return;
591        ntasks = nt;
592        cpu = c;
593}
594
595
596
597void check_vm_result(VixError err, VixHandle hostHandle, string errorString)
598{
599        if (VIX_OK != err)
600        {
601                fprintf (stderr, "\n\n Error: %s\n",errorString.c_str());
602                fprintf (stderr, "Error message: \"%s\"\n", Vix_GetErrorText (err, NULL));
603                VixHost_Disconnect (hostHandle);
604                boinc_finish(100);
605        }
606}
607
608int main (int argc, char **argv)
609{
610
611        BOINC_OPTIONS options;
612        int retval, ntasks;
613        unsigned int i;
614        double cpu, total_weight = 0, w = 0;
615
616        for (i = 1; i < (unsigned int) argc; i++)
617        {
618                if (!strcmp (argv[i], "--graphics"))
619                {
620                        graphics = true;
621                }
622        }
623
624        memset (&options, 0, sizeof (options));
625        options.main_program = true;
626        options.check_heartbeat = true;
627        options.handle_process_control = true;
628        if (graphics)
629        {
630                options.backwards_compatible_graphics = true;
631        }
632
633        // boinc_init_options(&options);
634
635        fprintf (stderr, "vmwrapper: starting\n");
636
637        boinc_get_init_data (aid);
638
639        retval = parse_job_file ();
640        if (retval)
641        {
642                fprintf (stderr, "can't parse job file: %d\n", retval);
643                boinc_finish (retval);
644        }
645
646        read_checkpoint (ntasks, cpu);
647        if (ntasks > (int) tasks.size ())
648        {
649                fprintf (stderr, "Checkpoint file: ntasks %d too large\n", ntasks);
650                boinc_finish (1);
651        }
652
653        for (i = 0; i < tasks.size (); i++)
654        {
655                total_weight += tasks[i].weight;
656        }
657
658
659
660
661        VixHandle hostHandle = VIX_INVALID_HANDLE;
662        VixHandle jobHandle = VIX_INVALID_HANDLE;
663        VixError err;
664        string vmxFilename;
665
666        jobHandle = VixHost_Connect (VIX_API_VERSION, VIX_SERVICEPROVIDER_VMWARE_SERVER, NULL, 0, NULL, NULL, 0, VIX_INVALID_HANDLE, NULL, NULL);
667
668        err = VixJob_Wait (jobHandle, VIX_PROPERTY_JOB_RESULT_HANDLE, &hostHandle, VIX_PROPERTY_NONE);
669
670        if (VIX_OK != err)
671        {
672                fprintf (stderr, "Unable to connect to server!\n");
673                fprintf (stderr, "Error message: \"%s\"\n", Vix_GetErrorText (err, NULL));
674                VixHost_Disconnect (hostHandle);
675                boinc_finish(1);
676        }
677
678        fprintf (stderr, "Connected to server.\n");
679
680
681        Vix_ReleaseHandle (jobHandle);
682        jobHandle = VIX_INVALID_HANDLE;
683
684
685        for (i = 0; i < tasks.size (); i++)
686        {
687
688                fprintf(stderr,"Processing task %d.\n", i);
689
690                TASK & task = tasks[i];
691
692                // w += task.weight;
693
694                // this line is to do with cpu time storage
695                // if ((int) i < ntasks)
696                //      continue;
697
698                double frac_done = w / total_weight;
699
700
701                fprintf(stderr, "Task %d.\n========\n\n", i+1);
702
703
704                fprintf(stderr, "VM file root is %s\n", task.vm.c_str ());
705
706                string vm_file_in_1, vm_file_in_2;
707                char vm_file_1[1024], vm_file_2[1024];
708
709                string pwd = get_current_dir_name ();
710
711
712                // VMWare Server 1 requires full path
713                vm_file_in_1 = pwd + "/" + task.vm + ".vmx";
714                vm_file_in_2 = pwd + "/" + task.vm + ".vmdk";
715
716//              fprintf (stderr, "Input filenames are %s, %s\n",
717//                      vm_file_in_1.c_str (), vm_file_in_2.c_str ());
718
719                boinc_resolve_filename (vm_file_in_1.c_str (), vm_file_1, 1024);
720                boinc_resolve_filename (vm_file_in_2.c_str (), vm_file_2, 1024);
721
722//              fprintf (stderr, "Resolved to %s, %s\n", vm_file_1, vm_file_2);
723
724                if (access (vm_file_1, R_OK))
725                {
726                        fprintf (stderr, "Unable to access VM file %s!\n",vm_file_1);
727                        boinc_finish (1);
728                }
729
730                if (access (vm_file_2, R_OK))
731                {
732                        fprintf (stderr, "Unable to access VM file %s!\n",vm_file_2);
733                        boinc_finish (1);
734                }
735
736
737                // Register VM
738                jobHandle = VixHost_RegisterVM (hostHandle, vm_file_1, NULL, NULL);
739                err = VixJob_Wait (jobHandle, VIX_PROPERTY_NONE);
740                check_vm_result(err, hostHandle, "Unable to register VM.");
741                fprintf (stderr, "Registered virtual machine with the server.\n");
742
743                VixHandle vmHandle = VIX_INVALID_HANDLE;
744
745                // Open VM
746                jobHandle = VixVM_Open (hostHandle, vm_file_1, NULL, NULL);
747                err = VixJob_Wait (jobHandle, VIX_PROPERTY_JOB_RESULT_HANDLE, &vmHandle, VIX_PROPERTY_NONE);
748                check_vm_result(err, hostHandle, "Unable to open VM.");
749                fprintf (stderr, "Got handle.\n");
750
751                // Power on VM
752                jobHandle = VixVM_PowerOn (vmHandle, 0, VIX_INVALID_HANDLE, NULL, NULL);
753                err = VixJob_Wait (jobHandle, VIX_PROPERTY_NONE);
754                check_vm_result(err, hostHandle, "Unable to power on VM.");
755                fprintf (stderr, "VM is now on (if it wasn't already).\n");
756
757                // Wait for guest OS to start
758                jobHandle = VixVM_WaitForToolsInGuest (vmHandle, 0, NULL, NULL);
759                err = VixJob_Wait (jobHandle, VIX_PROPERTY_NONE);
760                check_vm_result(err, hostHandle, "Did not get confirmation of VMWare Tools.");
761
762                // Log in
763                jobHandle = VixVM_LoginInGuest (vmHandle, task.user.c_str(), task.password.c_str(), 0, NULL, NULL);
764                err = VixJob_Wait (jobHandle, VIX_PROPERTY_NONE);
765                check_vm_result(err, hostHandle, "Unable to log in.");
766                fprintf (stderr, "Logged in. Preparing job...\n");
767
768
769                string guestfile = task.datadir +  "/" + task.innerjob;
770                string st_hostfile = pwd + "/" + task.innerjob;
771                char hostfile[1024];
772
773                boinc_resolve_filename (st_hostfile.c_str (), hostfile, 1024);
774
775                jobHandle = VixVM_CopyFileFromHostToGuest (vmHandle, hostfile, guestfile.c_str(), 0, VIX_INVALID_HANDLE, NULL, NULL);
776                err = VixJob_Wait (jobHandle, VIX_PROPERTY_NONE);
777                check_vm_result(err, hostHandle, "Unable to copy executable.");
778
779                Vix_ReleaseHandle (jobHandle);
780
781                // Changing permissions, do we really need to do this?
782                jobHandle = VixVM_RunProgramInGuest (vmHandle, "/bin/chmod", ("+x " + guestfile).c_str (), 0, VIX_INVALID_HANDLE, NULL, NULL); 
783                err = VixJob_Wait (jobHandle, VIX_PROPERTY_NONE);
784                check_vm_result(err, hostHandle, "Unable to change permissions.");
785
786                Vix_ReleaseHandle (jobHandle);
787
788
789                fprintf (stderr, "Copying in input...\n");
790
791                for(int files=0;files<task.data.size();files++)
792                {
793                        fprintf(stderr,"Processing: %s\n",task.data[files].c_str());
794
795                        // should use boinc_resolve_filename here
796                        jobHandle = VixVM_CopyFileFromHostToGuest (vmHandle, (pwd + "/" + task.data[files]).c_str(), (task.datadir + "/" + task.data[files]).c_str(),
797                                0, VIX_INVALID_HANDLE,  NULL, NULL);
798                        err = VixJob_Wait (jobHandle, VIX_PROPERTY_NONE);
799                        check_vm_result(err, hostHandle, "Error copying in file.");
800
801                        Vix_ReleaseHandle (jobHandle);
802
803                }
804
805
806
807
808
809
810                // Run the target program.
811                fprintf (stderr, "Running main program: ");
812                jobHandle = VixVM_RunProgramInGuest (vmHandle, guestfile.c_str (), "", 0, VIX_INVALID_HANDLE, NULL, NULL);
813
814                Bool complete=false;
815
816                task.starting_cpu = cpu;
817                task.checkpoint_cpu_time = cpu;
818
819
820                BOINC_STATUS status;
821                VixHandle innerJobHandle;
822                VixHandle snapshotHandle;
823
824                while(!complete)
825                {
826                        if(boinc_time_to_checkpoint())
827                                fprintf(stderr,"Time to checkpoint run here...\n");
828
829
830
831                        boinc_get_status (&status);
832
833                        if (status.no_heartbeat || status.quit_request || status.abort_request)
834                        {
835                                VixHost_Disconnect (hostHandle);
836                                boinc_finish(0);
837                        }
838
839
840                        // contents of this control structure needs fixing, since suspend doesn't work
841                        if (status.suspended)
842                        {
843                                if (!task.suspended)
844                                {
845                                        // innerJobHandle = VixVM_Suspend(vmHandle,0,VIX_INVALID_HANDLE,NULL,NULL);
846                                        // err = VixJob_Wait(innerJobHandle, VIX_PROPERTY_JOB_RESULT_HANDLE, &snapshotHandle, VIX_PROPERTY_NONE);
847                                        // check_vm_result(err, hostHandle, "Error pausing VM.");
848                                        task.stop();
849                                }
850                        }
851                        else
852                        {
853                                if (task.suspended)
854                                {
855                                        // innerJobHandle = VixVM_Unpause(vmHandle,0,VIX_INVALID_HANDLE,NULL,NULL);
856                                        // err = VixJob_Wait(innerJobHandle, VIX_PROPERTY_JOB_RESULT_HANDLE, &snapshotHandle, VIX_PROPERTY_NONE);
857                                        // check_vm_result(err, hostHandle, "Error unpausing VM.");
858                                        task.resume ();
859                                }
860                        }
861
862
863                        // send_status_message (task, frac_done);
864                        // fprintf(stderr,"Partial credit check here...\n");
865
866                        // double current_cpu_time = task.starting_cpu + task.cpu_time ();
867
868                        // if (task.has_checkpointed ())
869                        // {
870                        //      task.checkpoint_cpu_time = current_cpu_time;
871                        // }
872
873                        // not sure how to do this yet
874                        // boinc_report_app_status (current_cpu_time, task.checkpoint_cpu_time, frac_done);
875
876
877                        boinc_sleep(POLL_PERIOD);
878
879
880                        if(!task.suspended) {
881                                err = VixJob_CheckCompletion(jobHandle, &complete);
882                                check_vm_result(err, hostHandle, "Error polling for job completion.");
883                        }
884                }
885
886
887                cpu += task.final_cpu_time;
888                // write_checkpoint here is necessary to keep track of CPU time
889                // we either use the time measured, or the time from within
890                write_checkpoint (i + 1, cpu);
891
892                err = VixJob_Wait (jobHandle, VIX_PROPERTY_NONE);
893                check_vm_result(err, hostHandle, "Error running target program.");
894                fprintf (stderr, "done.\n");
895
896
897
898
899                Vix_ReleaseHandle (jobHandle);
900
901       
902                fprintf(stderr, "Copying out output...\n");
903
904                for(int files=0;files<task.output.size();files++)
905                {
906                        fprintf(stderr,"Processing: %s\n",task.output[files].c_str());
907
908
909                        // FIXME: need to tell BOINC about these files
910                        jobHandle = VixVM_CopyFileFromGuestToHost (vmHandle, (task.datadir + "/" + task.output[0]).c_str(), 
911                                (pwd + "/" + task.output[files]).c_str (), 0, VIX_INVALID_HANDLE, NULL, NULL);
912                        err = VixJob_Wait (jobHandle, VIX_PROPERTY_NONE);
913                        check_vm_result(err, hostHandle, "Error copying out file.");
914
915                        Vix_ReleaseHandle (jobHandle);
916
917                        jobHandle = VixVM_RunProgramInGuest (vmHandle, "/bin/rm",  (task.datadir + "/" + task.output[files]).c_str(), 0, VIX_INVALID_HANDLE, NULL, NULL);       
918                        err = VixJob_Wait (jobHandle, VIX_PROPERTY_NONE);
919                        check_vm_result(err, hostHandle, "Error deleting file.");
920
921                        Vix_ReleaseHandle (jobHandle);
922                }
923
924
925                // now delete the executable, the output and the data
926                fprintf(stderr, "Sanitising virtual machine...\n");
927
928                for(int files=0;files<task.data.size();files++)
929                {
930                        fprintf(stderr,"Removing: %s\n",task.data[files].c_str());
931
932                        jobHandle = VixVM_RunProgramInGuest (vmHandle, "/bin/rm",  (task.datadir + "/" + task.data[files]).c_str(), 0, VIX_INVALID_HANDLE, NULL, NULL); 
933                        err = VixJob_Wait (jobHandle, VIX_PROPERTY_NONE);
934                        check_vm_result(err, hostHandle, "Error deleting file.");
935
936                        Vix_ReleaseHandle (jobHandle);
937                }
938
939
940                fprintf(stderr,"Removing executable.\n");
941                jobHandle = VixVM_RunProgramInGuest (vmHandle, "/bin/rm",  guestfile.c_str(), 0, VIX_INVALID_HANDLE, NULL, NULL);       
942                err = VixJob_Wait (jobHandle, VIX_PROPERTY_NONE);
943                check_vm_result(err, hostHandle, "Error deleting file.");
944
945                Vix_ReleaseHandle (jobHandle);
946
947       
948
949        }
950
951        boinc_finish (0);
952}
953
954
955#ifdef _WIN32
956
957int WINAPI
958WinMain (HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR Args, int WinMode)
959{
960        LPSTR command_line;
961        char *argv[100];
962        int argc;
963
964        command_line = GetCommandLine ();
965        argc = parse_command_line (command_line, argv);
966        return main (argc, argv);
967}
968#endif