pthread_cond_t queue_cond;
// A mutex that protects the todo tasks queue from being accessed in
// read/write by two threads at the same time.
- pthread_mutex_t tasks_todo_mutex;
+ mutable pthread_mutex_t tasks_todo_mutex;
// A mutex that protects the done tasks queue from being accessed in
// read/write by two threads at the same time.
pthread_mutex_t tasks_done_mutex;
notify(n)
{create_workers();}
+ /// Tests if there are more tasks to execute from the task queue.
+ ///
+ /// @return true iff there are more tasks to execute.
+ bool
+ more_tasks_to_execute() const
+ {
+ pthread_mutex_lock(&tasks_todo_mutex);
+ bool result = !tasks_todo.empty();
+ pthread_mutex_unlock(&tasks_todo_mutex);
+ return result;
+ }
+
/// Create the worker threads pool and have all threads sit idle,
/// waiting for a task to be added to the todo queue.
void
if (workers.empty())
return;
- pthread_mutex_lock(&tasks_todo_mutex);
- bring_workers_down = true;
- pthread_mutex_unlock(&tasks_todo_mutex);
-
// Acquire the mutex that protects the queue condition variable
// (queue_cond) and wake up all the workers that are sleeping on
// the condition.
pthread_mutex_lock(&queue_cond_mutex);
+ bring_workers_down = true;
assert(pthread_cond_broadcast(&queue_cond) == 0);
pthread_mutex_unlock(&queue_cond_mutex);
queue::priv*
worker::wait_to_execute_a_task(queue::priv* p)
{
- pthread_mutex_lock(&p->tasks_todo_mutex);
- bool more_tasks = !p->tasks_todo.empty();
- bool bring_workers_down = p->bring_workers_down;
- pthread_mutex_unlock(&p->tasks_todo_mutex);
+
+ pthread_mutex_lock(&p->queue_cond_mutex);
do
{
// If there is no more tasks to perform and the queue is not to
// be brought down then wait (sleep) for new tasks to come up.
- while (!more_tasks && !bring_workers_down)
- {
- pthread_mutex_lock(&p->queue_cond_mutex);
- pthread_cond_wait(&p->queue_cond, &p->queue_cond_mutex);
- pthread_mutex_unlock(&p->queue_cond_mutex);
-
- pthread_mutex_lock(&p->tasks_todo_mutex);
- more_tasks = !p->tasks_todo.empty();
- bring_workers_down = p->bring_workers_down;
- pthread_mutex_unlock(&p->tasks_todo_mutex);
- }
-
+ while (!p->more_tasks_to_execute() && !p->bring_workers_down)
+ pthread_cond_wait(&p->queue_cond, &p->queue_cond_mutex);
// We were woken up. So maybe there are tasks to perform? If
// so, get a task from the queue ...
p->notify(t);
pthread_mutex_unlock(&p->tasks_done_mutex);
}
-
- pthread_mutex_lock(&p->tasks_todo_mutex);
- more_tasks = !p->tasks_todo.empty();
- bring_workers_down = p->bring_workers_down;
- pthread_mutex_unlock(&p->tasks_todo_mutex);
}
- while (!p->bring_workers_down || more_tasks);
+ while (!p->bring_workers_down || p->more_tasks_to_execute());
+
+ pthread_mutex_unlock(&p->queue_cond_mutex);
return p;
}
#include <iostream>
#include <cstdlib>
#include <cstring>
+#include <vector>
#include "abg-ir.h"
#include "abg-reader.h"
#include "abg-writer.h"
+#include "abg-workers.h"
#include "abg-tools-utils.h"
#include "test-utils.h"
using std::string;
+using std::vector;
using std::ofstream;
using std::cerr;
+using std::tr1::dynamic_pointer_cast;
+
using abigail::tools_utils::file_type;
using abigail::tools_utils::check_file;
using abigail::tools_utils::guess_file_type;
using abigail::xml_writer::write_translation_unit;
using abigail::xml_writer::write_corpus_to_native_xml;
+using abigail::workers::queue;
+using abigail::workers::task;
+using abigail::workers::task_sptr;
+using abigail::workers::get_number_of_threads;
+
/// This is an aggregate that specifies where a test shall get its
/// input from, and where it shall write its ouput to.
struct InOutSpec
{NULL, NULL, NULL, NULL}
};
+/// A task wihch reads an abixml file using abilint and compares its
+/// output against a reference output.
+struct test_task : public abigail::workers::task
+{
+ InOutSpec spec;
+ bool is_ok;
+ string in_path, out_path, in_suppr_spec_path, ref_out_path;
+ string diff_cmd, error_message;
+
+ /// Constructor of the task.
+ ///
+ /// @param the spec of where to find the abixml file to read and the
+ /// reference output of the test.
+ test_task( InOutSpec& s)
+ : spec(s),
+ is_ok(true)
+ {}
+
+ /// This method defines what the task performs.
+ virtual void
+ perform()
+ {
+ string input_suffix(spec.in_path);
+ in_path =
+ string(abigail::tests::get_src_dir()) + "/tests/" + input_suffix;
+
+ if (!check_file(in_path, cerr))
+ {
+ is_ok = false;
+ return;
+ }
+
+ string ref_out_path_suffix(spec.ref_out_path);
+ ref_out_path =
+ string(abigail::tests::get_src_dir())
+ + "/tests/" + ref_out_path_suffix;
+
+ if (!check_file(ref_out_path, cerr))
+ {
+ is_ok = false;
+ return;
+ }
+
+ if (spec.in_suppr_spec_path && strcmp(spec.in_suppr_spec_path, ""))
+ {
+ in_suppr_spec_path = string(spec.in_suppr_spec_path);
+ in_suppr_spec_path =
+ string(abigail::tests::get_src_dir())
+ + "/tests/"
+ + in_suppr_spec_path;
+ }
+ else
+ in_suppr_spec_path.clear();
+
+ environment_sptr env(new environment);
+ translation_unit_sptr tu;
+ corpus_sptr corpus;
+
+ file_type t = guess_file_type(in_path);
+ if (t == abigail::tools_utils::FILE_TYPE_UNKNOWN)
+ {
+ cerr << in_path << "is an unknown file type\n";
+ is_ok = false;
+ return;
+ }
+
+ string output_suffix(spec.out_path);
+ out_path =
+ string(abigail::tests::get_build_dir()) + "/tests/" + output_suffix;
+ if (!abigail::tools_utils::ensure_parent_dir_created(out_path))
+ {
+ error_message =
+ "Could not create parent director for " + out_path;
+ is_ok = false;
+ return;
+ }
+
+ string abilint = string(get_build_dir()) + "/tools/abilint";
+ if (!in_suppr_spec_path.empty())
+ abilint +=string(" --suppr ") + in_suppr_spec_path;
+ string cmd = abilint + " " + in_path + " > " + out_path;
+
+ if (system(cmd.c_str()))
+ {
+ error_message =
+ "ABI XML file doesn't pass abilint: " + out_path + "\n";
+ is_ok = false;
+ }
+
+ cmd = "diff -u " + ref_out_path + " " + out_path;
+ diff_cmd = cmd;
+ if (system(cmd.c_str()))
+ is_ok = false;
+ }
+};// end struct test_task
+
+/// A convenience typedef for shared
+typedef shared_ptr<test_task> test_task_sptr;
+
/// Walk the array of InOutSpecs above, read the input files it points
/// to, write it into the output it points to and diff them.
int
main()
{
- unsigned result = 1;
+ using abigail::workers::queue;
+ using abigail::workers::task;
+ using abigail::workers::task_sptr;
+ using abigail::workers::get_number_of_threads;
+
+ const size_t num_tests = sizeof(in_out_specs) / sizeof (InOutSpec) - 1;
+ size_t num_workers = std::min(get_number_of_threads(), num_tests);
+ queue task_queue(num_workers);
bool is_ok = true;
+
+
string in_path, out_path, in_suppr_spec_path, ref_out_path;
for (InOutSpec* s = in_out_specs; s->in_path; ++s)
{
- string input_suffix(s->in_path);
- in_path =
- string(abigail::tests::get_src_dir()) + "/tests/" + input_suffix;
-
- if (!check_file(in_path, cerr))
- return true;
+ test_task_sptr t(new test_task(*s));
+ assert(task_queue.schedule_task(t));
+ }
- string ref_out_path_suffix(s->ref_out_path);
- ref_out_path =
- string(abigail::tests::get_src_dir())
- + "/tests/" + ref_out_path_suffix;
+ /// Wait for all worker threads to finish their job, and wind down.
+ task_queue.wait_for_workers_to_complete();
- if (!check_file(ref_out_path, cerr))
- return true;
+ // Now walk the results and print whatever error messages need to be
+ // printed.
- if (s->in_suppr_spec_path && strcmp(s->in_suppr_spec_path, ""))
- {
- in_suppr_spec_path = string(s->in_suppr_spec_path);
- in_suppr_spec_path =
- string(abigail::tests::get_src_dir())
- + "/tests/"
- + in_suppr_spec_path;
- }
- else
- in_suppr_spec_path.clear();
+ const vector<task_sptr>& completed_tasks =
+ task_queue.get_completed_tasks();
- environment_sptr env(new environment);
- translation_unit_sptr tu;
- corpus_sptr corpus;
+ assert(completed_tasks.size() == num_tests);
- file_type t = guess_file_type(in_path);
- if (t == abigail::tools_utils::FILE_TYPE_UNKNOWN)
- {
- cerr << in_path << "is an unknown file type\n";
- is_ok = false;
- continue;
- }
-
- string output_suffix(s->out_path);
- out_path =
- string(abigail::tests::get_build_dir()) + "/tests/" + output_suffix;
- if (!abigail::tools_utils::ensure_parent_dir_created(out_path))
+ for (vector<task_sptr>::const_iterator ti = completed_tasks.begin();
+ ti != completed_tasks.end();
+ ++ti)
+ {
+ test_task_sptr t = dynamic_pointer_cast<test_task>(*ti);
+ if (!t->is_ok)
{
- cerr << "Could not create parent director for " << out_path;
is_ok = false;
- return result;
- }
- string abilint = string(get_build_dir()) + "/tools/abilint";
- if (!in_suppr_spec_path.empty())
- abilint +=string(" --suppr ") + in_suppr_spec_path;
- string cmd = abilint + " " + in_path + " > " + out_path;
+ if (!t->error_message.empty())
+ cerr << t->error_message << '\n';
- if (system(cmd.c_str()))
- {
- cerr << "ABI XML file doesn't pass abilint: " << out_path << "\n";
- is_ok &= false;
+ if (!t->diff_cmd.empty())
+ system(t->diff_cmd.c_str());
}
-
- cmd = "diff -u " + ref_out_path + " " + out_path;
- if (system(cmd.c_str()))
- is_ok &= false;
}
return !is_ok;