blob: 6a79597f5de44aef869afcc7e3660f858cfa30c5 [file] [log] [blame]
/*
* Copyright (c) 2011-2014, Intel Corporation
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation and/or
* other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors
* may be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "TestPlatform.h"
#include "FullIo.hpp"
#include <iostream>
#include <cstdlib>
#include <semaphore.h>
#include <string.h>
#include <unistd.h>
#include <cerrno>
#include <cassert>
using namespace std;
const int iDefaultPortNumber = 5001;
// Starts test-platform in blocking mode
static bool startBlockingTestPlatform(const char *filePath, int portNumber, string &strError)
{
// Init semaphore
sem_t sem;
sem_init(&sem, false, 0);
// Create param mgr
CTestPlatform testPlatform(filePath, portNumber, sem);
// Start platformmgr
if (!testPlatform.load(strError)) {
sem_destroy(&sem);
return false;
}
// Block here
sem_wait(&sem);
sem_destroy(&sem);
return true;
}
static void notifyParent(int parentFd, bool success)
{
if (not utility::fullWrite(parentFd, &success, sizeof(success))) {
cerr << "Unable to warn parent process of load "
<< (success ? "success" : "failure") << ": "
<< strerror(errno) << endl;
assert(false);
}
}
// Starts test-platform in daemon mode
static bool startDaemonTestPlatform(const char *filePath, int portNumber, string &strError)
{
// Pipe used for communication between the child and the parent processes
int pipefd[2];
if (pipe(pipefd) == -1) {
strError = "pipe failed";
return false;
}
// Fork the current process:
// - Child process is used to start test-platform
// - Parent process is killed in order to turn its child into a daemon
pid_t pid = fork();
if (pid < 0) {
strError = "fork failed!";
return false;
} else if (pid == 0) {
// Child process : starts test-platform and notify the parent if it succeeds.
// Close read side of the pipe
close(pipefd[0]);
// Init semaphore
sem_t sem;
sem_init(&sem, false, 0);
// Create param mgr
CTestPlatform testPlatform(filePath, portNumber, sem);
// Message to send to parent process
bool loadSuccess = testPlatform.load(strError);
if (!loadSuccess) {
cerr << strError << endl;
// Notify parent of failure;
notifyParent(pipefd[1], false);
} else {
// Notify parent of success
notifyParent(pipefd[1], true);
// Block here
sem_wait(&sem);
}
sem_destroy(&sem);
return loadSuccess;
} else {
// Parent process : need to kill it once the child notifies the successs/failure to start
// test-platform (this status is used as exit value of the program).
// Close write side of the pipe
close(pipefd[1]);
// Message received from the child process
bool msgFromChild = false;
if (not utility::fullRead(pipefd[0], &msgFromChild, sizeof(msgFromChild))) {
strError = "Read pipe failed";
return false;
}
// return success/failure in exit status
return msgFromChild;
}
}
static void showUsage()
{
cerr << "test-platform [-dh] <file path> [port number, default "
<< iDefaultPortNumber << "]" << endl;
}
static void showInvalidUsage()
{
cerr << "Invalid arguments: ";
showUsage();
}
static void showHelp()
{
showUsage();
cerr << "<file path> must be a valid .xml file, oftenly ParameterFrameworkConfiguration.xml" << endl;
cerr << "Arguments:" << endl
<< " -d starts as a deamon" << endl
<< " -h display this help and exit" << endl;
}
int main(int argc, char *argv[])
{
// Option found by call to getopt()
int opt;
// Port number to be used by test-platform
int portNumber;
// Daemon flag
bool isDaemon = false;
// Index of the <file path> argument in the arguments list provided
int indexFilePath = 1;
// Handle the -d option
while ((opt = getopt(argc, argv, "dh")) != -1) {
switch (opt) {
case 'd':
isDaemon = true;
indexFilePath = 2;
break;
case 'h':
showHelp();
return 0;
default:
showInvalidUsage();
return -1;
}
}
// Check the number of arguments
if ((argc < indexFilePath + 1) || (argc > indexFilePath + 2)) {
showInvalidUsage();
return -1;
}
char *filePath = argv[indexFilePath];
portNumber = argc > indexFilePath + 1 ? atoi(argv[indexFilePath + 1]) : iDefaultPortNumber;
// Choose either blocking or daemon test-platform
bool startError;
string strError;
if (isDaemon) {
startError = startDaemonTestPlatform(filePath, portNumber, strError);
} else {
startError = startBlockingTestPlatform(filePath, portNumber, strError);
}
if (!startError) {
cerr << "Test-platform error:" << strError.c_str() << endl;
return -1;
}
return 0;
}