forked from huawei/mindspore2022
186 lines
5.2 KiB
C++
186 lines
5.2 KiB
C++
/**
|
|
* Copyright 2019 Huawei Technologies Co., Ltd
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
#ifndef DATASET_UTIL_TASK_MANAGER_H_
|
|
#define DATASET_UTIL_TASK_MANAGER_H_
|
|
|
|
#include <semaphore.h>
|
|
#include <signal.h> // for sig_atomic_t
|
|
#include <condition_variable>
|
|
#include <functional>
|
|
#include <memory>
|
|
#include <string>
|
|
#include <set>
|
|
#include "dataset/util/allocator.h"
|
|
#include "dataset/util/intrp_service.h"
|
|
#include "dataset/util/lock.h"
|
|
#include "dataset/util/services.h"
|
|
#include "dataset/util/status.h"
|
|
#include "dataset/util/task.h"
|
|
|
|
namespace mindspore {
|
|
namespace dataset {
|
|
namespace thread {
|
|
using id = std::thread::id;
|
|
} // namespace thread
|
|
|
|
namespace this_thread {
|
|
inline thread::id get_id() { return std::this_thread::get_id(); }
|
|
} // namespace this_thread
|
|
|
|
class TaskManager : public Service {
|
|
public:
|
|
friend class Services;
|
|
|
|
friend class TaskGroup;
|
|
|
|
~TaskManager() override;
|
|
|
|
TaskManager(const TaskManager &) = delete;
|
|
|
|
TaskManager &operator=(const TaskManager &) = delete;
|
|
|
|
static TaskManager &GetInstance() noexcept { return Services::getTaskMgrInstance(); }
|
|
|
|
Status DoServiceStart() override;
|
|
|
|
Status DoServiceStop() override;
|
|
|
|
// A public global interrupt flag for signal handlers
|
|
volatile sig_atomic_t global_interrupt_;
|
|
|
|
// API
|
|
// This takes the same parameter as Task constructor. Take a look
|
|
// of the test-thread.cc for usage.
|
|
Status CreateAsyncTask(const std::string &my_name, const std::function<Status()> &f, TaskGroup *vg, Task **);
|
|
|
|
// Same usage as boot thread group
|
|
Status join_all();
|
|
|
|
void interrupt_all() noexcept;
|
|
|
|
// Locate a particular Task.
|
|
static Task *FindMe();
|
|
|
|
static void InterruptGroup(Task &);
|
|
|
|
static Status GetMasterThreadRc();
|
|
|
|
static void InterruptMaster(const Status &rc = Status::OK());
|
|
|
|
static void WakeUpWatchDog() {
|
|
TaskManager &tm = TaskManager::GetInstance();
|
|
(void)sem_post(&tm.sem_);
|
|
}
|
|
|
|
void ReturnFreeTask(Task *p) noexcept;
|
|
|
|
Status GetFreeTask(const std::string &my_name, const std::function<Status()> &f, Task **p);
|
|
|
|
Status WatchDog();
|
|
|
|
private:
|
|
RWLock lru_lock_;
|
|
SpinLock free_lock_;
|
|
SpinLock tg_lock_;
|
|
std::shared_ptr<Task> master_;
|
|
List<Task> lru_;
|
|
List<Task> free_lst_;
|
|
sem_t sem_;
|
|
TaskGroup *watchdog_grp_;
|
|
std::set<TaskGroup *> grp_list_;
|
|
Task *watchdog_;
|
|
|
|
TaskManager();
|
|
};
|
|
|
|
// A group of related tasks.
|
|
class TaskGroup : public Service {
|
|
public:
|
|
friend class Task;
|
|
friend class TaskManager;
|
|
|
|
Status CreateAsyncTask(const std::string &my_name, const std::function<Status()> &f, Task **pTask = nullptr);
|
|
|
|
void interrupt_all() noexcept;
|
|
|
|
Status join_all();
|
|
|
|
int size() const noexcept { return grp_list_.count; }
|
|
|
|
Status DoServiceStart() override { return Status::OK(); }
|
|
|
|
Status DoServiceStop() override;
|
|
|
|
TaskGroup();
|
|
|
|
~TaskGroup() override;
|
|
|
|
Status GetTaskErrorIfAny();
|
|
|
|
std::shared_ptr<IntrpService> GetIntrpService();
|
|
|
|
private:
|
|
Status rc_;
|
|
// Can't use rw_lock_ as we will lead to deadlatch. Create another mutex to serialize access to rc_.
|
|
std::mutex rc_mux_;
|
|
RWLock rw_lock_;
|
|
List<Task> grp_list_;
|
|
std::shared_ptr<IntrpService> intrp_svc_;
|
|
};
|
|
|
|
namespace this_thread {
|
|
inline bool is_interrupted() {
|
|
TaskManager &tm = TaskManager::GetInstance();
|
|
if (tm.global_interrupt_ == 1) {
|
|
return true;
|
|
}
|
|
Task *my_task = TaskManager::FindMe();
|
|
return (my_task != nullptr) ? my_task->Interrupted() : false;
|
|
}
|
|
} // namespace this_thread
|
|
|
|
#define RETURN_IF_INTERRUPTED() \
|
|
do { \
|
|
if (mindspore::dataset::this_thread::is_interrupted()) { \
|
|
Task *myTask = TaskManager::FindMe(); \
|
|
if (myTask->IsMasterThread() && myTask->CaughtSevereException()) { \
|
|
return TaskManager::GetMasterThreadRc(); \
|
|
} else { \
|
|
return Status(StatusCode::kInterrupted); \
|
|
} \
|
|
} \
|
|
} while (false)
|
|
|
|
inline Status interruptible_wait(std::condition_variable *cv, std::unique_lock<std::mutex> *lk,
|
|
const std::function<bool()> &pred) noexcept {
|
|
if (!pred()) {
|
|
do {
|
|
RETURN_IF_INTERRUPTED();
|
|
try {
|
|
(void)cv->wait_for(*lk, std::chrono::milliseconds(1));
|
|
} catch (std::exception &e) {
|
|
// Anything thrown by wait_for is considered system error.
|
|
RETURN_STATUS_UNEXPECTED(e.what());
|
|
}
|
|
} while (!pred());
|
|
}
|
|
return Status::OK();
|
|
}
|
|
} // namespace dataset
|
|
} // namespace mindspore
|
|
|
|
#endif // DATASET_UTIL_TASK_MANAGER_H_
|