summaryrefslogtreecommitdiff
path: root/tools/build-automation/slave.nw
diff options
context:
space:
mode:
Diffstat (limited to 'tools/build-automation/slave.nw')
-rw-r--r--tools/build-automation/slave.nw340
1 files changed, 340 insertions, 0 deletions
diff --git a/tools/build-automation/slave.nw b/tools/build-automation/slave.nw
new file mode 100644
index 0000000000000..bcdfbd8a4aaf4
--- /dev/null
+++ b/tools/build-automation/slave.nw
@@ -0,0 +1,340 @@
+% -*- mode: Noweb; -*-
+%
+% $Id: slave.nw 2561 2012-08-31 02:46:33Z jkoshy $
+%
+% The build slave.
+
+\chapter{The Build Slave}\label{chap.slave}
+
+\section{Overview}
+
+\paragraph{File structure}
+
+The implementation of the \tool{yabs} slave is structured along
+conventional lines.
+
+<<slave/slave.c>>=
+<<generated file warning>>
+<<slave: include headers>>
+<<slave: declare types and constants>>
+<<slave: define helper functions>>
+<<slave: define main()>>
+@
+
+\section{Data Types}
+
+The data structures used in the \tool{yabs} slave are:
+
+\begin{itemize}
+\item A data structure to record command-line options
+ ([[struct slave_options]]).
+\item Others...(TBD).
+\end{itemize}
+
+<<slave: declare types and constants>>=
+<<define common constants>>
+<<slave: declare slave options>>
+@
+
+\paragraph{Slave Options}\label{para:slave-options}
+
+The [[slave_options]] structure is used to track the options
+controlling the slave's behavior.
+
+This structure is populated in the \func{main} function.
+
+<<slave: declare slave options>>=
+struct slave_options {
+ char *sl_id;
+ unsigned long sl_port;
+ const char *sl_server;
+ enum yabs_server_type sl_servertype;
+ int sl_verbose;
+};
+@ %def slave_options
+
+\begin{itemize}
+\item The \var{sl\_id} member specifies the identifier that the slave
+ sends to the \tool{yabs} despatcher at connect time.
+
+ The default identifier is the system's hostname (see chunk
+ [[<<slave: set the slave identifier if not set>>]]). The ``-i''
+ option is used to change the identifier (see [[<<slave: handle -i>>]]).
+\item The \var{sl\_port} field specifies the TCP port on the server
+ running the \tool{yabs} despatcher that the slave should connect to.
+ This is overrideable by the ``-p'' command-line option (see
+ [[<<slave: handle -p>>]]).
+\item The \var{sl\_server} field specifies the server to connect to.
+ The \var{sc\_servertype} field specifies whether to use a TCP
+ connection, a local socket, or to use standard input and output
+ (see [[enum yabs_server_type]]).
+\item The \var{sl\_verbose} field specifies the verbosity level for
+ the slave.
+\end{itemize}
+
+<<slave: initialize option structure>>=
+options.sl_id = NULL;
+options.sl_port = YABS_DEFAULT_DESPATCHER_PORT;
+options.sl_server = NULL;
+options.sl_servertype = YABS_SERVER_STDIN;
+options.sl_verbose = 0;
+@
+
+\section{The Program Entry Point}
+
+<<slave: define main()>>=
+int
+main(int argc, char **argv)
+{
+ <<slave: main: local variables>>
+ <<slave: initialize option structure>>
+ <<slave: parse options>>
+ <<slave: invoke libevent main loop>>
+ return (0);
+}
+@ %def main
+
+The [[<<slave: main: local variables>>]] chunk declares the local
+variables needed by the function.
+
+\paragraph{Option Parsing}
+
+Option parsing uses the POSIX \func{getopt} API. The end result of
+the option parsing is an appropriately configured [[slave_options]]
+structure.
+
+<<slave: main: local variables>>=
+struct slave_options options;
+int option;
+@
+
+<<slave: parse options>>=
+while ((option = getopt(argc, argv, "hi:p:vV")) != -1) {
+ switch (option) {
+ case 'h':
+ display_usage_message(); exit(0);
+ break;
+ case 'i':
+ <<slave: handle -i>>
+ break;
+ case 'p':
+ <<slave: handle -p>>
+ break;
+ case 'v':
+ <<slave: handle -v>>
+ break;
+ case 'V':
+ <<slave: handle -V>>
+ break;
+ case '?':
+ display_usage_message(); exit(1);
+ break;
+ default:
+ errx(1, "FATAL: Unrecognized option value %c (%d)",
+ option, option);
+ break;
+ }
+}
+
+<<slave: set the slave identifier if not set>>
+@
+
+\paragraph{Handling ``-i''}
+The identifier by which the slave identifies itself to the despatcher
+can be set using the ``-i'' option. If this option is specified
+multiple times, the last one takes precedence.
+
+<<slave: handle -i>>=
+if (options.sl_id)
+ free(options.sl_id);
+options.sl_id = strdup(optarg);
+@
+
+\paragraph{Handling ``-p''}
+The ``-p'' option is used to specify the port the slave should connect
+to. It is required to be a decimal number: we use the \func{strtoul}
+function to convert the option argument to a number.
+
+<<slave: main: local variables>>=
+char *end;
+@
+
+<<slave: handle -p>>=
+options.sl_port = strtoul(optarg, &end, 10);
+if (options.sl_port == 0 || *end != '\0')
+ errx(1, "Invalid port number \"%s\"", optarg);
+@
+
+\paragraph{Handling ``-v'''}
+The ``-v'' option increases verbosity. The current verbosity level is
+recorded in the \var{sc\_verbose} field.
+
+<<slave: handle -v>>=
+options.sl_verbose++;
+@
+
+\paragraph{Handling ``-V''}
+The ``-V'' option prints a version number, and exits.
+
+<<slave: declare types and constants>>=
+#define YABS_SLAVE_NAME "yabs-slave"
+@ %def YABS_SLAVE_NAME
+
+<<slave: handle -V>>=
+(void) printf(YABS_SLAVE_NAME " " YABS_SLAVE_VERSION " (Protocol: "
+ YABS_PROTOCOL_VERSION ")\n");
+exit(0);
+@
+
+\paragraph{Setting a default identifier}
+
+If an identifier was not specified by a '-i' command line option, we
+use the name of the host the slave is running on.
+
+<<slave: set the slave identifier if not set>>=
+if (options.sl_id == NULL) {
+ <<slave: allocate space for the slave identifier>>
+ <<slave: retrieve the host name>>
+}
+@
+
+<<slave: allocate space for the slave identifier>>=
+if ((options.sl_id = malloc(HOST_NAME_MAX)) == NULL)
+ err(1, "malloc failed: [%s,%d]", __FILE__, __LINE__);
+@
+
+The system's host name is retrieved using the \func{gethostname} library
+function. We explicitly NUL-terminate the array after calling \func{gethostname},
+since portable programs cannot assume that function does so for host names
+that are exactly HOST\_NAME\_MAX bytes long.
+
+<<slave: retrieve the host name>>=
+if (gethostname(options.sl_id, HOST_NAME_MAX) < 0)
+ err(1, "gethostname failed: [%s,%d]", __FILE__, __LINE__);
+options.sl_id[HOST_NAME_MAX - 1] = '\0';
+@
+
+\paragraph{Invoking libevent}
+
+<<slave: invoke libevent main loop>>=
+event_base_loop((void *) 0, 0);
+@
+\section{Helper Functions}
+
+<<slave: define helper functions>>=
+void
+display_usage_message(void)
+{
+ (void) printf("usage: " YABS_SLAVE_NAME " [options] [server]\n\n" \
+ "Supported options:\n" \
+ " -h\t\tPrint a help message and exit.\n" \
+ " -i ID\tUse ID as an identifier [host name]\n" \
+ " -p PORT\tConnect to port PORT on the server [0x4242].\n" \
+ " -v\t\tBe more verbose.\n" \
+ " -V\t\tPrint a version identifier and exit.\n");
+}
+@ %def display_usage_message
+
+\section{Header Inclusions}
+
+The use of the \func{errx} family of functions requires the standard
+header \file{err.h}.
+
+<<slave: include headers>>=
+#include <err.h>
+@
+
+The \var{HOST\_NAME\_MAX} constant used in the chunk
+[[<<slave: set the slave identifier if not set>>]] is
+defined by the \file{limits.h} header.
+
+<<slave: include headers>>=
+#include <limits.h>
+@
+
+
+The use of the \func{printf} function requires the use of the system
+header \file{stdio.h}.
+
+<<slave: include headers>>=
+#include <stdio.h>
+@
+
+The header file \file{stdlib.h} is needed for the prototypes for the
+\func{exit}, \func{free} and \func{malloc} functions.
+
+<<slave: include headers>>=
+#include <stdlib.h>
+@
+
+The header file \file{string.h} provides the prototype for
+\func{strdup} used in chunk [[<<Handling ``-i''>>]].
+
+<<slave: include headers>>=
+#include <string.h>
+@
+
+The header file \file{unistd.h} is needed for the prototype for the
+\func{getopt} function used in chunk [[<<slave: parse options>>]].
+
+<<slave: include headers>>=
+#include <unistd.h>
+@
+
+\tool{Libevent} specific headers are needed for the libevent APIs:
+<<slave: include headers>>=
+#include <event2/event.h>
+@
+
+
+\section{Build Rules}
+
+Using the facilities provided by the standard rules in
+\verb|<bsd.prog.mk>|, a simple \file{Makefile} suffices to build the
+slave.
+
+The \file{Makefile} indicates that the generated progam is to be
+called \tool{yabs-slave} and that the file \file{slave.c} is the
+source file to be compiled. The contents of this source file is
+defined by the chunk [[<<slave/slave.c>>]].
+
+<<slave/Makefile>>=
+PROG= yabs-slave
+SRCS= slave.c
+
+CFLAGS+= -Wall -Wextra -Werror -pedantic
+<<make: libevent related definitions>>
+
+.include <bsd.prog.mk>
+
+<<make: override debug flags during development>>
+@
+
+We look in a set of standard locations to determine where the headers
+and library files for \tool{libevent} are located.
+
+<<make: libevent related definitions>>=
+.if exists(${HOME}/local/include/event2)
+LIBEVENT_INCLUDE= -I ${HOME}/local/include
+LIBEVENT_LIB= -L ${HOME}/local/lib
+.elif exists(/usr/local/include/event2)
+LIBEVENT_INCLUDE= -I /usr/local/include
+LIBEVENT_LIB= -L /usr/local/lib
+.endif
+
+CFLAGS+= ${LIBEVENT_INCLUDE}
+LDADD+= ${LIBEVENT_LIB} -levent
+@
+
+Debugging is simpler if compiler optimizations are turned off. We
+thus remove the \term{-O2} flag during development.
+
+<<make: override debug flags during development>>=
+CFLAGS:= ${CFLAGS:N-O2} -g
+LDFLAGS+= -g
+@
+
+% Local Variables:
+% noweb-code-mode: c-mode
+% c-electric-flag: nil
+% End: