mirror of https://github.com/BOINC/boinc.git
Ignore generated files
Remove the checkpoint from the client - it is not the goal of this example Fix the XML descriptions Add a header for definitions common to the client and the master Make the master periodically send messages until the result is received git-svn-id: svn+ssh://cvs.lpds.sztaki.hu/var/lib/svn/szdg/dcapi/trunk@804 a7169a2c-3604-0410-bc95-c702d8d87f7a
This commit is contained in:
parent
95a98aebae
commit
9948e538b5
|
@ -18,11 +18,11 @@ endif
|
|||
|
||||
CLEANFILES = message-example-client.xml message-example-master.xml
|
||||
|
||||
message_example_client_SOURCES = client.c
|
||||
message_example_client_SOURCES = client.c common.h
|
||||
message_example_client_CPPFLAGS = $(DCAPI_CLIENT_CFLAGS)
|
||||
message_example_client_LDADD = $(DCAPI_CLIENT_LIBS)
|
||||
|
||||
message_example_master_SOURCES = master.c
|
||||
message_example_master_SOURCES = master.c common.h
|
||||
message_example_master_CPPFLAGS = $(DCAPI_MASTER_CFLAGS)
|
||||
message_example_master_LDADD = $(DCAPI_MASTER_LIBS)
|
||||
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include <dc_client.h>
|
||||
|
||||
#include <unistd.h>
|
||||
|
@ -5,80 +9,27 @@
|
|||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
|
||||
/* The logical file names, used at sequencial application */
|
||||
#define INPUT_NAME "in.txt"
|
||||
#define OUTPUT_NAME "out.txt"
|
||||
#include "common.h"
|
||||
|
||||
static FILE *infile;
|
||||
static FILE *outfile;
|
||||
|
||||
/* Needed to report the percentage of the work already done */
|
||||
static int frac_total_size;
|
||||
static int frac_current_pos;
|
||||
|
||||
static int message_has_arrived = 0;
|
||||
|
||||
/* Save the value of frac_current_pos to the ckpt file */
|
||||
static void do_checkpoint(void)
|
||||
{
|
||||
char *ckptfile_name;
|
||||
FILE *ckptfile;
|
||||
int retval;
|
||||
|
||||
/* Ensure that the output file is really on the disk before we create
|
||||
* the checkpoint file */
|
||||
retval = fflush(outfile);
|
||||
if (retval)
|
||||
{
|
||||
perror("APP: flushing the output file has failed");
|
||||
DC_finishClient(1);
|
||||
}
|
||||
|
||||
ckptfile_name = DC_resolveFileName(DC_FILE_OUT, DC_CHECKPOINT_FILE);
|
||||
if (!ckptfile_name)
|
||||
{
|
||||
fprintf(stderr, "APP: Could not resolve the checkpoint file "
|
||||
"name\n");
|
||||
DC_finishClient(1);
|
||||
}
|
||||
|
||||
ckptfile = fopen(ckptfile_name, "w");
|
||||
if (!ckptfile)
|
||||
{
|
||||
perror("APP: Could not create the checkpoint file");
|
||||
DC_finishClient(1);
|
||||
}
|
||||
|
||||
fprintf(ckptfile, "%d", frac_current_pos);
|
||||
retval = fclose(ckptfile);
|
||||
if (retval)
|
||||
{
|
||||
perror("APP: Closing the checkpoint file has failed");
|
||||
DC_finishClient(1);
|
||||
}
|
||||
|
||||
/* Tell the DC-API that the checkpoint is ready */
|
||||
DC_checkpointMade(ckptfile_name);
|
||||
|
||||
/* Update the estimation about the work done */
|
||||
DC_fractionDone(frac_current_pos/frac_total_size);
|
||||
}
|
||||
static int messages_received;
|
||||
|
||||
/* Open input and output files, and check is there is a checkpoint file */
|
||||
static void init_files(void)
|
||||
{
|
||||
const char *outfile_openmode = "w";
|
||||
char *file_name;
|
||||
|
||||
/* Open the input file */
|
||||
file_name = DC_resolveFileName(DC_FILE_IN, INPUT_NAME);
|
||||
file_name = DC_resolveFileName(DC_FILE_IN, INPUT_LABEL);
|
||||
if (!file_name)
|
||||
{
|
||||
fprintf(stderr, "APP: Could not resolve the input file name\n");
|
||||
DC_finishClient(1);
|
||||
}
|
||||
|
||||
infile = fopen(file_name, "rb");
|
||||
infile = fopen(file_name, "r");
|
||||
if (!infile)
|
||||
{
|
||||
perror("APP: Could not open the input file");
|
||||
|
@ -86,80 +37,38 @@ static void init_files(void)
|
|||
}
|
||||
free(file_name);
|
||||
|
||||
/* Determine the size of the input file */
|
||||
fseek(infile, 0, SEEK_END);
|
||||
frac_total_size = ftell(infile);
|
||||
fseek(infile, 0, SEEK_SET);
|
||||
|
||||
/* Check the checkpoint file */
|
||||
file_name = DC_resolveFileName(DC_FILE_IN, DC_CHECKPOINT_FILE);
|
||||
if (file_name)
|
||||
{
|
||||
FILE *ckptfile;
|
||||
int ret;
|
||||
|
||||
ckptfile = fopen(file_name, "r");
|
||||
if (!ckptfile)
|
||||
{
|
||||
perror("APP: Could not open the initial checkpoint file");
|
||||
DC_finishClient(1);
|
||||
}
|
||||
free(file_name);
|
||||
|
||||
/* ckpt file exists: read and set everything according to it */
|
||||
ret = fscanf(ckptfile, "%d", &frac_current_pos);
|
||||
if (ret != 1 || frac_current_pos < 0 ||
|
||||
frac_current_pos > frac_total_size)
|
||||
{
|
||||
fprintf(stderr, "APP: Failed to parse the contents of "
|
||||
"the checkpoint file, starting from the "
|
||||
"beginning\n");
|
||||
frac_current_pos = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(stderr, "APP: Found checkpoint file, starting "
|
||||
"from position %d.\n", frac_current_pos);
|
||||
outfile_openmode = "r+";
|
||||
}
|
||||
fclose(ckptfile);
|
||||
|
||||
fseek(infile, frac_current_pos, SEEK_SET);
|
||||
}
|
||||
|
||||
/* Open the output file */
|
||||
file_name = DC_resolveFileName(DC_FILE_OUT, OUTPUT_NAME);
|
||||
file_name = DC_resolveFileName(DC_FILE_OUT, OUTPUT_LABEL);
|
||||
if (!file_name)
|
||||
{
|
||||
fprintf(stderr, "APP: Could not resolve the output file name\n");
|
||||
DC_finishClient(1);
|
||||
}
|
||||
|
||||
outfile = fopen(file_name, outfile_openmode);
|
||||
outfile = fopen(file_name, "w");
|
||||
if (!outfile)
|
||||
{
|
||||
perror("APP: Could not open/create the output file");
|
||||
DC_finishClient(1);
|
||||
}
|
||||
free(file_name);
|
||||
|
||||
/* If we are starting from a checkpoint file, restore the state of
|
||||
* the output file as well */
|
||||
ftruncate(fileno(outfile), frac_current_pos);
|
||||
fseek(outfile, 0, SEEK_END);
|
||||
}
|
||||
|
||||
static void message_arrived(char *message)
|
||||
static void message_arrived(const char *message)
|
||||
{
|
||||
fprintf(stderr, "APP: message: '%s' arrived\n", message);
|
||||
DC_sendMessage("This is a sample reply message");
|
||||
fprintf(stderr, "APP: message: 'This is a sample reply message' sent\n");
|
||||
message_has_arrived = 1;
|
||||
char reply[256];
|
||||
|
||||
fprintf(stderr, "APP: message: '%s' arrived, sending reply\n", message);
|
||||
|
||||
snprintf(reply, sizeof(reply), "Reply to: %s", message);
|
||||
DC_sendMessage(reply);
|
||||
messages_received++;
|
||||
}
|
||||
|
||||
/* The real work */
|
||||
static void do_work(void)
|
||||
{
|
||||
char buf[32];
|
||||
int c;
|
||||
|
||||
while ((c = fgetc(infile)) != EOF)
|
||||
|
@ -172,11 +81,16 @@ static void do_work(void)
|
|||
perror("APP: fputc");
|
||||
DC_finishClient(1);
|
||||
}
|
||||
frac_current_pos++;
|
||||
|
||||
/* Send the just-converted character to the master. This in
|
||||
* turn also allows receiving messages from the master */
|
||||
snprintf(buf, sizeof(buf), "Processed %c", c);
|
||||
DC_sendMessage(buf);
|
||||
|
||||
/* Real applications do real computation that takes time. Here
|
||||
* we just emulate it */
|
||||
sleep(5);
|
||||
* we just emulate it. We sleep for a long time to prevent
|
||||
* sending messages too often. */
|
||||
sleep(30);
|
||||
|
||||
/* Check if either the master or the BOINC core client asked
|
||||
* us to do something */
|
||||
|
@ -184,11 +98,12 @@ static void do_work(void)
|
|||
if (!event)
|
||||
continue;
|
||||
|
||||
/* If it is time, do a checkpoint */
|
||||
if (event->type == DC_CLIENT_CHECKPOINT)
|
||||
do_checkpoint();
|
||||
|
||||
if (event->type == DC_CLIENT_MESSAGE)
|
||||
{
|
||||
DC_log(LOG_INFO, "Checkpoint request received");
|
||||
DC_checkpointMade(NULL);
|
||||
}
|
||||
else if (event->type == DC_CLIENT_MESSAGE)
|
||||
message_arrived(event->message);
|
||||
|
||||
/* Make sure we do not leak memory */
|
||||
|
@ -213,14 +128,14 @@ int main(int argc, char *argv[])
|
|||
"value was %d\n", retval);
|
||||
DC_finishClient(1);
|
||||
}
|
||||
fprintf(stderr, "APP: DC-API initialization was successful.\n");
|
||||
fprintf(stdout, "APP: DC-API initialization was successful.\n");
|
||||
|
||||
init_files();
|
||||
do_work();
|
||||
fprintf(stderr, "APP: Work finished.\n");
|
||||
|
||||
if (!message_has_arrived)
|
||||
fprintf(stderr, "APP: Hasn't receaved any message from the master !!!\n");
|
||||
do_work();
|
||||
|
||||
fprintf(stdout, "APP: Work finished. Received %d messages from the "
|
||||
"master.\n", messages_received);
|
||||
|
||||
DC_finishClient(0);
|
||||
return(0); // Tho' we never reach this line
|
||||
|
@ -230,13 +145,11 @@ int main(int argc, char *argv[])
|
|||
int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR Args, int WinMode)
|
||||
{
|
||||
LPSTR command_line;
|
||||
char* argv[100];
|
||||
char *argv[100];
|
||||
int argc;
|
||||
|
||||
command_line = GetCommandLine();
|
||||
argc = parse_command_line( command_line, argv );
|
||||
argc = parse_command_line(command_line, argv);
|
||||
return main(argc, argv);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
/*
|
||||
* Common definitions used by both the master and the client
|
||||
*/
|
||||
|
||||
#ifndef COMMON_H
|
||||
#define COMMON_H
|
||||
|
||||
/* Logical names of the input/output files */
|
||||
#define INPUT_LABEL "in.txt"
|
||||
#define OUTPUT_LABEL "out.txt"
|
||||
|
||||
#endif /* COMMON_H */
|
|
@ -20,6 +20,10 @@
|
|||
*
|
||||
*****************************************************/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include <dc.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
|
@ -29,13 +33,7 @@
|
|||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
|
||||
#define INPUT_LABEL "in.txt"
|
||||
#define OUTPUT_LABEL "out.txt"
|
||||
|
||||
/* Number of WUs we have created */
|
||||
static int created_wus;
|
||||
/* Number of results we have received so far */
|
||||
static int processed_wus;
|
||||
#include "common.h"
|
||||
|
||||
/* Command line options */
|
||||
static const struct option longopts[] =
|
||||
|
@ -45,27 +43,22 @@ static const struct option longopts[] =
|
|||
{ NULL }
|
||||
};
|
||||
|
||||
static int do_exit;
|
||||
|
||||
static void process_result(DC_Workunit *wu, DC_Result *result)
|
||||
{
|
||||
char *tag;
|
||||
|
||||
/* Internal housekeeping of the number of results we have seen */
|
||||
processed_wus++;
|
||||
|
||||
/* Extract our own private identifier */
|
||||
tag = DC_getWUTag(wu);
|
||||
|
||||
DC_log(LOG_NOTICE, "Work unit %s has completed", tag);
|
||||
|
||||
/* We no longer need the work unit */
|
||||
DC_destroyWU(wu);
|
||||
|
||||
free(tag);
|
||||
}
|
||||
|
||||
static void process_subresult(DC_Workunit *wu, const char *logicalFileName, const char *path)
|
||||
{
|
||||
/* There is no subresult in this example */
|
||||
/* This will cause the main loop to quit */
|
||||
do_exit = 1;
|
||||
}
|
||||
|
||||
static void process_message(DC_Workunit *wu, const char *message)
|
||||
|
@ -78,9 +71,8 @@ static void process_message(DC_Workunit *wu, const char *message)
|
|||
free(tag);
|
||||
}
|
||||
|
||||
static void create_work(void)
|
||||
static DC_Workunit *create_work(void)
|
||||
{
|
||||
char ch;
|
||||
DC_Workunit *wu;
|
||||
|
||||
wu = DC_createWU("message-example", NULL, 0, "message-test");
|
||||
|
@ -108,12 +100,7 @@ static void create_work(void)
|
|||
exit(1);
|
||||
}
|
||||
|
||||
created_wus++;
|
||||
|
||||
printf("Press ENTER, after this WU is downloaded by a BOINC client");
|
||||
ch = getchar();
|
||||
|
||||
DC_sendWUMessage(wu, "This is a test message");
|
||||
return wu;
|
||||
}
|
||||
|
||||
static void print_help(const char *prog) __attribute__((noreturn));
|
||||
|
@ -136,6 +123,7 @@ static void print_help(const char *prog)
|
|||
int main(int argc, char *argv[])
|
||||
{
|
||||
char *config_file = NULL;
|
||||
DC_Workunit *wu;
|
||||
int c;
|
||||
|
||||
while ((c = getopt_long(argc, argv, "ch", longopts, NULL)) != -1)
|
||||
|
@ -174,17 +162,23 @@ int main(int argc, char *argv[])
|
|||
exit(1);
|
||||
}
|
||||
|
||||
/* We need the result callback function only */
|
||||
DC_setMasterCb(process_result, process_subresult, process_message);
|
||||
/* Set the callbacks for receiving messages & the result */
|
||||
DC_setMasterCb(process_result, NULL, process_message);
|
||||
|
||||
DC_log(LOG_NOTICE, "Master: Creating work unit");
|
||||
create_work();
|
||||
wu = create_work();
|
||||
DC_log(LOG_NOTICE, "Master: Work unit has been created. Waiting "
|
||||
"for result/message ...\n");
|
||||
"for result/message");
|
||||
|
||||
/* Wait for the work units to finish */
|
||||
while (processed_wus < created_wus)
|
||||
DC_processMasterEvents(600);
|
||||
while (!do_exit)
|
||||
{
|
||||
DC_processMasterEvents(60);
|
||||
|
||||
/* The result processing destroys the WU, so make sure we
|
||||
* only try to send a message if the WU is still alive */
|
||||
if (!do_exit)
|
||||
DC_sendWUMessage(wu, "What's up?");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
<?xml version="1.0" standalone="no"?>
|
||||
<client>
|
||||
<!-- Application name -->
|
||||
<name>uppercase-example</name>
|
||||
<name>message-example</name>
|
||||
|
||||
<!-- User-friendly name for Boinc -->
|
||||
<user_friendly_name>Uppercase Example Application with callback functions</user_friendly_name>
|
||||
<user_friendly_name>Messaging example</user_friendly_name>
|
||||
|
||||
<!-- Application version. Boinc requirements:
|
||||
- The version number must contain two components (major.minor)
|
||||
|
@ -19,14 +19,9 @@
|
|||
|
||||
<!-- The name of the main client binary. It will be
|
||||
automatically renamed to the name expected by Boinc -->
|
||||
<binary>uppercase-example-client</binary>
|
||||
|
||||
<!-- Signature of the main binary, if the code signing key
|
||||
is not present at the machine running the project -->
|
||||
<!-- <signarute>@appdir@/search.sig</signature> -->
|
||||
<binary>message-example-client</binary>
|
||||
|
||||
<!-- Additional files can also be installed -->
|
||||
<!-- <lib>winlib.dll</lib> -->
|
||||
<!-- <lib>winlib.dll.sig</lib> -->
|
||||
</platform>
|
||||
</client>
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
<?xml version="1.0" standalone="no"?>
|
||||
<!--
|
||||
Configuration template for the uppercase example application
|
||||
Configuration template for the message example application
|
||||
-->
|
||||
<master>
|
||||
<!-- Application name -->
|
||||
<name>uppercase-example</name>
|
||||
<name>message-example</name>
|
||||
|
||||
<!-- Application version. There are no restrictions for the format of
|
||||
master version numbers -->
|
||||
|
@ -17,7 +17,7 @@
|
|||
|
||||
<!-- Master daemon definition -->
|
||||
<daemon>
|
||||
<binary>uppercase-example-master</binary>
|
||||
<binary>message-example-master</binary>
|
||||
<arguments>
|
||||
<arg>--config</arg>
|
||||
<arg>${workdir}/dc-api.conf</arg>
|
||||
|
@ -35,7 +35,7 @@
|
|||
<arg>-d</arg>
|
||||
<arg>3</arg>
|
||||
<arg>-app</arg>
|
||||
<arg>uppercase-example</arg>
|
||||
<arg>message-example</arg>
|
||||
</arguments>
|
||||
</daemon>
|
||||
</master>
|
||||
|
|
Loading…
Reference in New Issue