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 License
16 // along with BOINC. If not, see <http://www.gnu.org/licenses/>.
17
18 // This program serves as both
19 // - An example BOINC application, illustrating the use of the BOINC API
20 // - A program for testing various features of BOINC
21 //
22 // NOTE: this file exists as both
23 // boinc/apps/upper_case.cpp
24 // and
25 // boinc_samples/example_app/uc2.cpp
26 // If you update one, please update the other!
27
28 // The program converts a mixed-case file to upper case:
29 // read "in", convert to upper case, write to "out"
30 //
31 // command line options
32 // -run_slow: sleep 1 second after each character
33 // -cpu_time N: use about N CPU seconds after copying files
34 // -early_exit: exit(10) after 30 chars
35 // -early_crash: crash after 30 chars
36 //
37
38 #ifdef _WIN32
39 #include "boinc_win.h"
40 #else
41 #include "config.h"
42 #include <cstdio>
43 #include <cctype>
44 #include <ctime>
45 #include <cstring>
46 #include <cstdlib>
47 #include <csignal>
48 #include <unistd.h>
49 #endif
50
51 #include "str_util.h"
52 #include "util.h"
53 #include "filesys.h"
54 #include "boinc_api.h"
55 #include "mfile.h"
56 #include "graphics2.h"
57
58 #ifdef APP_GRAPHICS
59 #include "uc2.h"
60 UC_SHMEM* shmem;
61 #endif
62
63 using std::string;
64
65 #define CHECKPOINT_FILE "upper_case_state"
66 #define INPUT_FILENAME "in"
67 #define OUTPUT_FILENAME "out"
68
69 bool run_slow = false;
70 bool early_exit = false;
71 bool early_crash = false;
72 bool early_sleep = false;
73 double cpu_time = 20, comp_result;
74
75 // do a billion floating-point ops
76 // (note: I needed to add an arg to this;
77 // otherwise the MS C++ compiler optimizes away
78 // all but the first call to it!)
79 //
do_a_giga_flop(int foo)80 static double do_a_giga_flop(int foo) {
81 double x = 3.14159*foo;
82 int i;
83 for (i=0; i<500000000; i++) {
84 x += 5.12313123;
85 x *= 0.5398394834;
86 }
87 return x;
88 }
89
do_checkpoint(MFILE & mf,int nchars)90 int do_checkpoint(MFILE& mf, int nchars) {
91 int retval;
92 string resolved_name;
93
94 FILE* f = fopen("temp", "w");
95 if (!f) return 1;
96 fprintf(f, "%d", nchars);
97 fclose(f);
98
99 retval = mf.flush();
100 if (retval) return retval;
101 boinc_resolve_filename_s(CHECKPOINT_FILE, resolved_name);
102 retval = boinc_rename("temp", resolved_name.c_str());
103 if (retval) return retval;
104
105 return 0;
106 }
107
108 #ifdef APP_GRAPHICS
update_shmem()109 void update_shmem() {
110 if (!shmem) return;
111
112 // always do this; otherwise a graphics app will immediately
113 // assume we're not alive
114 shmem->update_time = dtime();
115
116 // Check whether a graphics app is running,
117 // and don't bother updating shmem if so.
118 // This doesn't matter here,
119 // but may be worth doing if updating shmem is expensive.
120 //
121 if (shmem->countdown > 0) {
122 // the graphics app sets this to 5 every time it renders a frame
123 shmem->countdown--;
124 } else {
125 return;
126 }
127 shmem->fraction_done = boinc_get_fraction_done();
128 shmem->cpu_time = boinc_worker_thread_cpu_time();;
129 boinc_get_status(&shmem->status);
130 }
131 #endif
132
main(int argc,char ** argv)133 int main(int argc, char **argv) {
134 int i;
135 int c, nchars = 0, retval, n;
136 double fsize, fd;
137 char input_path[512], output_path[512], chkpt_path[512], buf[256];
138 MFILE out;
139 FILE* state, *infile;
140
141 for (i=0; i<argc; i++) {
142 if (!strcmp(argv[i], "-early_exit")) early_exit = true;
143 if (!strcmp(argv[i], "-early_crash")) early_crash = true;
144 if (!strcmp(argv[i], "-early_sleep")) early_sleep = true;
145 if (!strcmp(argv[i], "-run_slow")) run_slow = true;
146 if (!strcmp(argv[i], "-cpu_time")) {
147 cpu_time = atof(argv[++i]);
148 }
149 }
150
151 retval = boinc_init();
152 if (retval) {
153 fprintf(stderr, "%s boinc_init returned %d\n",
154 boinc_msg_prefix(buf, sizeof(buf)), retval
155 );
156 exit(retval);
157 }
158
159 // open the input file (resolve logical name first)
160 //
161 boinc_resolve_filename(INPUT_FILENAME, input_path, sizeof(input_path));
162 infile = boinc_fopen(input_path, "r");
163 if (!infile) {
164 fprintf(stderr,
165 "%s Couldn't find input file, resolved name %s.\n",
166 boinc_msg_prefix(buf, sizeof(buf)), input_path
167 );
168 exit(-1);
169 }
170
171 // get size of input file (used to compute fraction done)
172 //
173 file_size(input_path, fsize);
174
175 boinc_resolve_filename(OUTPUT_FILENAME, output_path, sizeof(output_path));
176
177 // See if there's a valid checkpoint file.
178 // If so seek input file and truncate output file
179 //
180 boinc_resolve_filename(CHECKPOINT_FILE, chkpt_path, sizeof(chkpt_path));
181 state = boinc_fopen(chkpt_path, "r");
182 if (state) {
183 n = fscanf(state, "%d", &nchars);
184 fclose(state);
185 }
186 if (state && n==1) {
187 fseek(infile, nchars, SEEK_SET);
188 boinc_truncate(output_path, nchars);
189 retval = out.open(output_path, "ab");
190 } else {
191 retval = out.open(output_path, "wb");
192 }
193 if (retval) {
194 fprintf(stderr, "%s APP: upper_case output open failed:\n",
195 boinc_msg_prefix(buf, sizeof(buf))
196 );
197 fprintf(stderr, "%s resolved name %s, retval %d\n",
198 boinc_msg_prefix(buf, sizeof(buf)), output_path, retval
199 );
200 perror("open");
201 exit(1);
202 }
203
204 #ifdef APP_GRAPHICS
205 // create shared mem segment for graphics, and arrange to update it
206 //
207 shmem = (UC_SHMEM*)boinc_graphics_make_shmem("uppercase", sizeof(UC_SHMEM));
208 if (!shmem) {
209 fprintf(stderr, "%s failed to create shared mem segment\n",
210 boinc_msg_prefix(buf, sizeof(buf))
211 );
212 }
213 update_shmem();
214 boinc_register_timer_callback(update_shmem);
215 #endif
216
217 // main loop - read characters, convert to UC, write
218 //
219 for (i=0; ; i++) {
220 c = fgetc(infile);
221
222 if (c == EOF) break;
223 c = toupper(c);
224 out._putchar(c);
225 nchars++;
226 if (run_slow) {
227 boinc_sleep(1.);
228 }
229
230 if (early_exit && i>30) {
231 exit(-10);
232 }
233
234 if (early_crash && i>30) {
235 boinc_crash();
236 }
237 if (early_sleep && i>30) {
238 boinc_disable_timer_thread = true;
239 while (1) boinc_sleep(1);
240 }
241
242 if (boinc_time_to_checkpoint()) {
243 retval = do_checkpoint(out, nchars);
244 if (retval) {
245 fprintf(stderr, "%s APP: upper_case checkpoint failed %d\n",
246 boinc_msg_prefix(buf, sizeof(buf)), retval
247 );
248 exit(retval);
249 }
250 boinc_checkpoint_completed();
251 }
252
253 fd = nchars/fsize;
254 if (cpu_time) fd /= 2;
255 boinc_fraction_done(fd);
256 }
257
258 retval = out.flush();
259 if (retval) {
260 fprintf(stderr, "%s APP: upper_case flush failed %d\n",
261 boinc_msg_prefix(buf, sizeof(buf)), retval
262 );
263 exit(1);
264 }
265
266 // burn up some CPU time if needed
267 //
268 if (cpu_time) {
269 double start = dtime();
270 for (i=0; ; i++) {
271 double e = dtime()-start;
272 if (e > cpu_time) break;
273 fd = .5 + .5*(e/cpu_time);
274 boinc_fraction_done(fd);
275
276 if (boinc_time_to_checkpoint()) {
277 retval = do_checkpoint(out, nchars);
278 if (retval) {
279 fprintf(stderr, "%s APP: upper_case checkpoint failed %d\n",
280 boinc_msg_prefix(buf, sizeof(buf)), retval
281 );
282 exit(1);
283 }
284 boinc_checkpoint_completed();
285 }
286 comp_result = do_a_giga_flop(i);
287 }
288 }
289 boinc_fraction_done(1);
290 #ifdef APP_GRAPHICS
291 update_shmem();
292 #endif
293 boinc_finish(0);
294 }
295
296 #ifdef _WIN32
WinMain(HINSTANCE hInst,HINSTANCE hPrevInst,LPSTR Args,int WinMode)297 int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR Args, int WinMode) {
298 LPSTR command_line;
299 char* argv[100];
300 int argc;
301
302 command_line = GetCommandLine();
303 argc = parse_command_line( command_line, argv );
304 return main(argc, argv);
305 }
306 #endif
307
308 const char *BOINC_RCSID_33ac47a071 = "$Id$";
309
310