libabigail/include/abg-workers.h
Dodji Seketeli 1d85cc4546 Several fixes and enhancements to abigail::workers
While making abipkgdiff to use the abigail::workers API to do away
with using pthreads directory, it appeared that the abigail::workers
API needs fixes and enhancements.

Fixes
=====

* Don't try to schedule a task if the pointer to the task is nil

* Fix a data race when bringing workers (of a queue) down

* Always try to wake up all waiting threads when bringing down queue
  workers.

* Fix a data race when accessing the queue condition variable

* Fix a data race when notifying listeners about the end of the job
  performed by the task.

Enhancements
============

* Pass the "task done" notifier by reference, to the worker queue.

Without this, the worker queue needs to copy the "task done" notifier
by value.  This implies that user code needs to provide task done
notifier instances that come with potentially complicated copy
constructors.  By passing it by reference and by just re-using the
notifier from the user code, we do away with the need for copying
altogether.  This also fixes some latent copying bugs.

* Add a workers::queue::schedule_tasks() method

This allows user code to schedule a vector of tasks at once.

* make workers::queue::get_completed_tasks() return a non-const vector

This enables user code to sort the completed tasks as they wish.

	* include/abg-workers.h (queue::tasks_type): New typedef.
	(queue::queue): Pass task_done_notify by reference.
	(queue::schedule_tasks): Declare new member function.
	(queue::get_completed_tasks): Return non-const vector.
	* src/abg-workers.cc (queue::priv::default_notify): New data
	member.
	(queue::priv::notify): Make this data member be a reference.
	(queue::priv::priv): Initialize the notify data member to either
	the new default_notify (if no notifier is provided by the
	constructor) or to the notifier provided by the constructor.
	(queue::priv::schedule_task): Do not schedule a nil task.  Update
	comment.
	(queue::priv::schedule_tasks): Add a new member function.
	(queue::priv::do_bring_workers_down): Update comment.  Protect
	access to "bring_workers_down" with tasks_todo_mutex to prevent a
	data race.  Call pthread_cond_broadcast on the queue_cond
	unconditionaly to prevent some worker threads to keep waiting for
	ever. Also, protect the access to the queue_cond by the
	queue_cond_mutex to precent a data race.
	(queue::queue): Pass the notifier by reference. Update comment.
	(queue::schedule_task): Update comment.
	(queue::schedule_tasks): Define new member function.
	(queue::wait_for_workers_to_complete): Update comment.
	(queue::get_completed_tasks): Return a non-const vector. Update
	comment.
	(worker::wait_to_execute_a_task): Update several comments. Make
	the execution of the notification code to be synchronized (on the
	tasks_done_mutex).

Signed-off-by: Dodji Seketeli <dodji@redhat.com>
2017-02-27 09:48:08 +01:00

120 lines
3.4 KiB
C++

// -*- Mode: C++ -*-
//
// Copyright (C) 2013-2016 Red Hat, Inc.
//
// This file is part of the GNU Application Binary Interface Generic
// Analysis and Instrumentation Library (libabigail). This library is
// free software; you can redistribute it and/or modify it under the
// terms of the GNU Lesser General Public License as published by the
// Free Software Foundation; either version 3, or (at your option) any
// later version.
// This library is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Lesser Public License for more details.
// You should have received a copy of the GNU Lesser General Public
// License along with this program; see the file COPYING-LGPLV3. If
// not, see <http://www.gnu.org/licenses/>.
// Author: Dodji Seketeli
/// @file
///
/// This file declares an interface for the worker threads (or thread
/// pool) design pattern. It aims at performing a set of tasks in
/// parallel, using the multi-threading capabilities of the underlying
/// processor(s).
///
#ifndef __ABG_WORKERS_H__
#define __ABG_WORKERS_H__
#include <tr1/memory>
#include <vector>
using std::tr1::shared_ptr;
namespace abigail
{
/// The namespace of the worker threads (or thread pool)
/// implementation of libabigail. This was modelled after the article
/// https://en.wikipedia.org/wiki/Thread_pool.
namespace workers
{
class task;
typedef shared_ptr<task> task_sptr;
size_t get_number_of_threads();
/// This represents a task to be performed.
///
/// Each instance of this type represents a task that can be performed
/// concurrently to other instance of the same type.
///
/// An instance of @ref task is meant to be performed by a worker
/// (thread). A set of tasks can be stored in a @ref queue.
class task
{
public:
task();
virtual void
perform() = 0;
virtual ~task();
}; // end class task.
/// This represents a queue of tasks to be performed.
///
/// Tasks are performed by a number of worker threads.
///
/// When a task is inserted into a @ref queue, the task is said to be
/// "scheduled for execution".
///
/// This is because there are worker threads waiting for tasks to be
/// added to the queue. When a task is added to the queue, a worker
/// thread picks it up, executes it, notifies interested listeners
/// when the @ref task's execution is completed, and waits for another
/// task to be added to the queue.
///
/// Of course, several worker threads can execute tasks concurrently.
class queue
{
public:
struct priv;
typedef shared_ptr<priv> priv_sptr;
/// A convenience typedef for a vector of @ref task_sptr
typedef std::vector<task_sptr> tasks_type;
private:
priv_sptr p_;
public:
struct task_done_notify;
queue();
queue(unsigned number_of_workers);
queue(unsigned number_of_workers,
task_done_notify& notifier);
size_t get_size() const;
bool schedule_task(const task_sptr&);
bool schedule_tasks(const tasks_type&);
void wait_for_workers_to_complete();
tasks_type& get_completed_tasks() const;
~queue();
}; // end class queue
/// This functor is to notify listeners that a given task scheduled
/// for execution has been fully executed.
struct queue::task_done_notify
{
virtual void
operator()(const task_sptr& task_done);
};
} // end namespace workers
} // end namespace abigail
#endif // __ABG_WORKERS_H__