mirror of
https://github.com/topjohnwu/Magisk.git
synced 2025-01-04 16:17:39 +00:00
Remove magisklogd, use threads and BlockingQueue
This commit is contained in:
parent
b3242322fd
commit
3a422c3f15
@ -36,7 +36,7 @@ LOCAL_SRC_FILES := \
|
||||
core/img.cpp \
|
||||
core/magisk.cpp \
|
||||
core/daemon.cpp \
|
||||
core/log_daemon.cpp \
|
||||
core/logcat.cpp \
|
||||
core/bootstages.cpp \
|
||||
core/socket.cpp \
|
||||
core/db.cpp \
|
||||
|
@ -16,14 +16,15 @@
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
#include "magisk.h"
|
||||
#include "db.h"
|
||||
#include "utils.h"
|
||||
#include "img.h"
|
||||
#include "daemon.h"
|
||||
#include "resetprop.h"
|
||||
#include "selinux.h"
|
||||
#include "flags.h"
|
||||
#include <magisk.h>
|
||||
#include <db.h>
|
||||
#include <utils.h>
|
||||
#include <img.h>
|
||||
#include <daemon.h>
|
||||
#include <resetprop.h>
|
||||
#include <selinux.h>
|
||||
#include <flags.h>
|
||||
#include <logcat.h>
|
||||
|
||||
using namespace std;
|
||||
|
||||
@ -685,7 +686,7 @@ void post_fs_data(int client) {
|
||||
unblock_boot_process();
|
||||
}
|
||||
|
||||
start_log_daemon();
|
||||
start_logcat();
|
||||
|
||||
// Run common scripts
|
||||
LOGI("* Running post-fs-data.d scripts\n");
|
||||
|
@ -86,9 +86,6 @@ static void *request_handler(void *args) {
|
||||
case BOOT_COMPLETE:
|
||||
boot_complete(client);
|
||||
break;
|
||||
case HANDSHAKE:
|
||||
/* Do NOT close the client, make it hold */
|
||||
break;
|
||||
case SQLITE_CMD:
|
||||
exec_sql(client);
|
||||
close(client);
|
||||
|
@ -1,217 +0,0 @@
|
||||
/* log_daemon.c - A dedicated daemon to monitor logcat
|
||||
*
|
||||
* A universal logcat monitor for many usages. Add listeners to the list,
|
||||
* and the new log line will be sent through sockets to trigger
|
||||
* asynchronous events without polling
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <pthread.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/wait.h>
|
||||
#include <fcntl.h>
|
||||
#include <vector>
|
||||
|
||||
#include "magisk.h"
|
||||
#include "utils.h"
|
||||
#include "daemon.h"
|
||||
#include "flags.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
bool log_daemon_started = false;
|
||||
static vector<const char *> log_cmd, clear_cmd;
|
||||
static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
|
||||
|
||||
enum {
|
||||
HIDE_EVENT,
|
||||
LOG_EVENT
|
||||
};
|
||||
|
||||
#define EVENT_NUM 2
|
||||
|
||||
struct log_listener {
|
||||
int fd;
|
||||
bool (*filter)(const char *);
|
||||
};
|
||||
|
||||
static bool am_proc_start_filter(const char *log) {
|
||||
return strstr(log, "am_proc_start") != nullptr;
|
||||
}
|
||||
|
||||
static bool magisk_log_filter(const char *log) {
|
||||
return !am_proc_start_filter(log);
|
||||
}
|
||||
|
||||
static struct log_listener events[] = {
|
||||
{ /* HIDE_EVENT */
|
||||
.fd = -1,
|
||||
.filter = am_proc_start_filter
|
||||
},
|
||||
{ /* LOG_EVENT */
|
||||
.fd = -1,
|
||||
.filter = magisk_log_filter
|
||||
}
|
||||
};
|
||||
|
||||
static void sigpipe_handler(int) {
|
||||
close(events[HIDE_EVENT].fd);
|
||||
events[HIDE_EVENT].fd = -1;
|
||||
}
|
||||
|
||||
static void *monitor_thread(void *) {
|
||||
// Block SIGPIPE to prevent interruption
|
||||
sigset_t block_set;
|
||||
sigemptyset(&block_set);
|
||||
sigaddset(&block_set, SIGPIPE);
|
||||
pthread_sigmask(SIG_SETMASK, &block_set, nullptr);
|
||||
// Give the main daemon some time before we monitor it
|
||||
sleep(5);
|
||||
int fd;
|
||||
char b;
|
||||
while (true) {
|
||||
fd = connect_daemon();
|
||||
write_int(fd, HANDSHAKE);
|
||||
// This should hold unless the daemon is killed
|
||||
read(fd, &b, sizeof(b));
|
||||
// The main daemon crashed, spawn a new one
|
||||
close(fd);
|
||||
}
|
||||
}
|
||||
|
||||
static void *logcat_thread(void *) {
|
||||
int log_pid;
|
||||
char line[4096];
|
||||
while (true) {
|
||||
// Start logcat
|
||||
exec_t exec {
|
||||
.fd = -1,
|
||||
.argv = log_cmd.data()
|
||||
};
|
||||
log_pid = exec_command(exec);
|
||||
FILE *logs = fdopen(exec.fd, "r");
|
||||
while (fgets(line, sizeof(line), logs)) {
|
||||
if (line[0] == '-')
|
||||
continue;
|
||||
size_t len = strlen(line);
|
||||
pthread_mutex_lock(&lock);
|
||||
for (auto &event : events) {
|
||||
if (event.fd > 0 && event.filter(line))
|
||||
write(event.fd, line, len);
|
||||
}
|
||||
pthread_mutex_unlock(&lock);
|
||||
}
|
||||
|
||||
fclose(logs);
|
||||
kill(log_pid, SIGTERM);
|
||||
waitpid(log_pid, nullptr, 0);
|
||||
|
||||
LOGI("magisklogd: logcat output EOF");
|
||||
// Clear buffer
|
||||
exec_command_sync(clear_cmd.data());
|
||||
}
|
||||
}
|
||||
|
||||
static void log_daemon() {
|
||||
setsid();
|
||||
LOGI("Magisk v" xstr(MAGISK_VERSION) "(" xstr(MAGISK_VER_CODE) ") logger started\n");
|
||||
strcpy(argv0, "magisklogd");
|
||||
|
||||
// Set SIGPIPE handler
|
||||
struct sigaction act;
|
||||
memset(&act, 0, sizeof(act));
|
||||
act.sa_handler = sigpipe_handler;
|
||||
sigaction(SIGPIPE, &act, nullptr);
|
||||
|
||||
// Setup log dumps
|
||||
rename(LOGFILE, LOGFILE ".bak");
|
||||
events[LOG_EVENT].fd = xopen(LOGFILE, O_CREAT | O_WRONLY | O_TRUNC | O_CLOEXEC | O_APPEND, 0644);
|
||||
|
||||
// Construct cmdline
|
||||
log_cmd.push_back(MIRRDIR "/system/bin/logcat");
|
||||
// Test whether these buffers actually works
|
||||
const char *b[] = { "main", "events", "crash" };
|
||||
for (auto &buffer : b) {
|
||||
if (exec_command_sync(MIRRDIR "/system/bin/logcat", "-b", buffer, "-d", "-f", "/dev/null") == 0) {
|
||||
log_cmd.push_back("-b");
|
||||
log_cmd.push_back(buffer);
|
||||
}
|
||||
}
|
||||
chmod("/dev/null", 0666);
|
||||
clear_cmd = log_cmd;
|
||||
log_cmd.insert(log_cmd.end(), { "-v", "threadtime", "-s", "am_proc_start", "Magisk" });
|
||||
#ifdef MAGISK_DEBUG
|
||||
log_cmd.push_back("*:F");
|
||||
#endif
|
||||
log_cmd.push_back(nullptr);
|
||||
|
||||
clear_cmd.push_back("-c");
|
||||
clear_cmd.push_back(nullptr);
|
||||
|
||||
// Start worker threads
|
||||
pthread_t thread;
|
||||
pthread_create(&thread, nullptr, monitor_thread, nullptr);
|
||||
pthread_detach(thread);
|
||||
xpthread_create(&thread, nullptr, logcat_thread, nullptr);
|
||||
pthread_detach(thread);
|
||||
|
||||
// Handle socket requests
|
||||
struct sockaddr_un sun;
|
||||
socklen_t len = setup_sockaddr(&sun, LOG_SOCKET);
|
||||
int sockfd = xsocket(AF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0);
|
||||
if (xbind(sockfd, (struct sockaddr*) &sun, len))
|
||||
exit(1);
|
||||
xlisten(sockfd, 10);
|
||||
while(true) {
|
||||
int fd = xaccept4(sockfd, nullptr, nullptr, SOCK_CLOEXEC);
|
||||
struct ucred credential;
|
||||
get_client_cred(fd, &credential);
|
||||
if (credential.uid != 0) {
|
||||
// Do not allow non root clients
|
||||
close(fd);
|
||||
continue;
|
||||
}
|
||||
switch(read_int(fd)) {
|
||||
case HIDE_CONNECT:
|
||||
pthread_mutex_lock(&lock);
|
||||
close(events[HIDE_EVENT].fd);
|
||||
events[HIDE_EVENT].fd = fd;
|
||||
pthread_mutex_unlock(&lock);
|
||||
break;
|
||||
case HANDSHAKE:
|
||||
write_int(fd, HANDSHAKE);
|
||||
default:
|
||||
close(fd);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool start_log_daemon() {
|
||||
if (!log_daemon_started) {
|
||||
if (exec_command_sync(MIRRDIR "/system/bin/logcat", "-d", "-f", "/dev/null") == 0) {
|
||||
if (fork_dont_care() == 0)
|
||||
log_daemon();
|
||||
log_daemon_started = true;
|
||||
// Wait till we can connect to log_daemon and receive ack
|
||||
int fd = connect_log_daemon();
|
||||
write_int(fd, HANDSHAKE);
|
||||
read_int(fd);
|
||||
close(fd);
|
||||
}
|
||||
chmod("/dev/null", 0666);
|
||||
}
|
||||
return log_daemon_started;
|
||||
}
|
||||
|
||||
int connect_log_daemon() {
|
||||
if (!log_daemon_started)
|
||||
return -1;
|
||||
struct sockaddr_un sun;
|
||||
socklen_t len = setup_sockaddr(&sun, LOG_SOCKET);
|
||||
int fd = xsocket(AF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0);
|
||||
while (connect(fd, (struct sockaddr*) &sun, len))
|
||||
usleep(10000);
|
||||
return fd;
|
||||
}
|
125
native/jni/core/logcat.cpp
Normal file
125
native/jni/core/logcat.cpp
Normal file
@ -0,0 +1,125 @@
|
||||
#include <sys/wait.h>
|
||||
#include <sys/types.h>
|
||||
#include <signal.h>
|
||||
#include <vector>
|
||||
|
||||
#include <logcat.h>
|
||||
#include <utils.h>
|
||||
#include <logging.h>
|
||||
#include <magisk.h>
|
||||
|
||||
static std::vector<const char *> log_cmd, clear_cmd;
|
||||
static pthread_mutex_t event_lock = PTHREAD_MUTEX_INITIALIZER;
|
||||
bool logcat_started = false;
|
||||
|
||||
struct log_listener {
|
||||
bool enable = false;
|
||||
BlockingQueue<std::string> queue;
|
||||
bool (*filter)(const char *);
|
||||
};
|
||||
|
||||
static struct log_listener events[] = {
|
||||
{ /* HIDE_EVENT */
|
||||
.filter = [](auto log) -> bool { return strstr(log, "am_proc_start") != nullptr; }
|
||||
},
|
||||
{ /* LOG_EVENT */
|
||||
.filter = [](auto log) -> bool { return !strstr(log, "am_proc_start"); }
|
||||
}
|
||||
};
|
||||
|
||||
static void init_args() {
|
||||
// Construct cmdline
|
||||
log_cmd.push_back(MIRRDIR "/system/bin/logcat");
|
||||
// Test whether these buffers actually works
|
||||
const char *b[] = { "main", "events", "crash" };
|
||||
for (auto &buffer : b) {
|
||||
if (exec_command_sync(MIRRDIR "/system/bin/logcat", "-b", buffer, "-d", "-f", "/dev/null") == 0) {
|
||||
log_cmd.push_back("-b");
|
||||
log_cmd.push_back(buffer);
|
||||
}
|
||||
}
|
||||
chmod("/dev/null", 0666);
|
||||
clear_cmd = log_cmd;
|
||||
log_cmd.insert(log_cmd.end(), { "-v", "threadtime", "-s", "am_proc_start", "Magisk" });
|
||||
#ifdef MAGISK_DEBUG
|
||||
log_cmd.push_back("*:F");
|
||||
#endif
|
||||
log_cmd.push_back(nullptr);
|
||||
|
||||
clear_cmd.push_back("-c");
|
||||
clear_cmd.push_back(nullptr);
|
||||
}
|
||||
|
||||
static void *logcat_gobbler(void *) {
|
||||
int log_pid;
|
||||
char line[4096];
|
||||
while (true) {
|
||||
// Start logcat
|
||||
exec_t exec {
|
||||
.fd = -1,
|
||||
.argv = log_cmd.data()
|
||||
};
|
||||
log_pid = exec_command(exec);
|
||||
FILE *logs = fdopen(exec.fd, "r");
|
||||
while (fgets(line, sizeof(line), logs)) {
|
||||
if (line[0] == '-')
|
||||
continue;
|
||||
pthread_mutex_lock(&event_lock);
|
||||
for (auto &event : events) {
|
||||
if (event.enable && event.filter(line))
|
||||
event.queue.emplace_back(line);
|
||||
}
|
||||
pthread_mutex_unlock(&event_lock);
|
||||
}
|
||||
|
||||
fclose(logs);
|
||||
kill(log_pid, SIGTERM);
|
||||
waitpid(log_pid, nullptr, 0);
|
||||
|
||||
LOGI("magisklogd: logcat output EOF");
|
||||
// Clear buffer
|
||||
exec_command_sync(clear_cmd.data());
|
||||
}
|
||||
}
|
||||
|
||||
static void *log_writer(void *) {
|
||||
rename(LOGFILE, LOGFILE ".bak");
|
||||
FILE *log = xfopen(LOGFILE, "ae");
|
||||
setbuf(log, nullptr);
|
||||
auto &queue = start_logging(LOG_EVENT);
|
||||
while (true) {
|
||||
fprintf(log, "%s", queue.take().c_str());
|
||||
}
|
||||
}
|
||||
|
||||
BlockingQueue<std::string> &start_logging(logcat_event event) {
|
||||
pthread_mutex_lock(&event_lock);
|
||||
events[event].enable = true;
|
||||
pthread_mutex_unlock(&event_lock);
|
||||
return events[event].queue;
|
||||
}
|
||||
|
||||
void stop_logging(logcat_event event) {
|
||||
pthread_mutex_lock(&event_lock);
|
||||
events[event].enable = false;
|
||||
events[event].queue.clear();
|
||||
pthread_mutex_unlock(&event_lock);
|
||||
}
|
||||
|
||||
bool start_logcat() {
|
||||
if (logcat_started)
|
||||
return true;
|
||||
int test = exec_command_sync(MIRRDIR "/system/bin/logcat", "-d", "-f", "/dev/null");
|
||||
chmod("/dev/null", 0666);
|
||||
if (test != 0)
|
||||
return false;
|
||||
init_args();
|
||||
pthread_t t;
|
||||
pthread_create(&t, nullptr, log_writer, nullptr);
|
||||
pthread_detach(t);
|
||||
pthread_create(&t, nullptr, logcat_gobbler, nullptr);
|
||||
pthread_detach(t);
|
||||
logcat_started = true;
|
||||
return true;
|
||||
}
|
||||
|
@ -4,12 +4,12 @@
|
||||
#include <libgen.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "utils.h"
|
||||
#include "magisk.h"
|
||||
#include "daemon.h"
|
||||
#include "selinux.h"
|
||||
#include "db.h"
|
||||
#include "flags.h"
|
||||
#include <utils.h>
|
||||
#include <magisk.h>
|
||||
#include <daemon.h>
|
||||
#include <selinux.h>
|
||||
#include <db.h>
|
||||
#include <flags.h>
|
||||
|
||||
[[noreturn]] static void usage() {
|
||||
fprintf(stderr,
|
||||
@ -96,6 +96,11 @@ int magisk_main(int argc, char *argv[]) {
|
||||
send_fd(fd, STDOUT_FILENO);
|
||||
return read_int(fd);
|
||||
}
|
||||
|
||||
#if 0
|
||||
/* Entry point for testing stuffs */
|
||||
else if (strcmp(argv[1], "--test") == 0) {
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
usage();
|
||||
}
|
||||
|
@ -19,8 +19,6 @@ enum {
|
||||
LATE_START,
|
||||
BOOT_COMPLETE,
|
||||
MAGISKHIDE,
|
||||
HIDE_CONNECT,
|
||||
HANDSHAKE,
|
||||
SQLITE_CMD,
|
||||
};
|
||||
|
||||
@ -37,12 +35,6 @@ enum {
|
||||
int connect_daemon();
|
||||
int switch_mnt_ns(int pid);
|
||||
|
||||
// log_monitor.c
|
||||
|
||||
extern bool log_daemon_started;
|
||||
int connect_log_daemon();
|
||||
bool start_log_daemon();
|
||||
|
||||
// socket.c
|
||||
|
||||
socklen_t setup_sockaddr(struct sockaddr_un *sun, const char *name);
|
||||
@ -67,7 +59,6 @@ void write_key_token(int fd, const char *key, int tok);
|
||||
***************/
|
||||
|
||||
void unlock_blocks();
|
||||
void startup();
|
||||
void post_fs_data(int client);
|
||||
void late_start(int client);
|
||||
void boot_complete(int client);
|
||||
|
15
native/jni/include/logcat.h
Normal file
15
native/jni/include/logcat.h
Normal file
@ -0,0 +1,15 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <BlockingQueue.h>
|
||||
|
||||
enum logcat_event {
|
||||
HIDE_EVENT,
|
||||
LOG_EVENT
|
||||
};
|
||||
|
||||
extern bool logcat_started;
|
||||
|
||||
BlockingQueue<std::string> &start_logging(logcat_event event);
|
||||
void stop_logging(logcat_event event);
|
||||
bool start_logcat();
|
@ -8,12 +8,13 @@
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include "magisk.h"
|
||||
#include "utils.h"
|
||||
#include "resetprop.h"
|
||||
#include <magisk.h>
|
||||
#include <utils.h>
|
||||
#include <resetprop.h>
|
||||
#include <db.h>
|
||||
#include <logcat.h>
|
||||
|
||||
#include "magiskhide.h"
|
||||
#include "daemon.h"
|
||||
#include "db.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
@ -282,7 +283,7 @@ int launch_magiskhide(int client) {
|
||||
if (hide_enabled)
|
||||
return HIDE_IS_ENABLED;
|
||||
|
||||
if (!log_daemon_started)
|
||||
if (!logcat_started)
|
||||
return LOGCAT_DISABLED;
|
||||
|
||||
hide_enabled = true;
|
||||
@ -327,7 +328,7 @@ int stop_magiskhide() {
|
||||
}
|
||||
|
||||
void auto_start_magiskhide() {
|
||||
if (!start_log_daemon())
|
||||
if (!start_logcat())
|
||||
return;
|
||||
db_settings dbs;
|
||||
get_db_settings(&dbs, HIDE_CONFIG);
|
||||
|
@ -18,23 +18,22 @@
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
#include "magisk.h"
|
||||
#include "daemon.h"
|
||||
#include "utils.h"
|
||||
#include <magisk.h>
|
||||
#include <utils.h>
|
||||
#include <logcat.h>
|
||||
|
||||
#include "magiskhide.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
static int sockfd = -1;
|
||||
extern char *system_block, *vendor_block, *magiskloop;
|
||||
|
||||
// Workaround for the lack of pthread_cancel
|
||||
static void term_thread(int) {
|
||||
LOGD("proc_monitor: running cleanup\n");
|
||||
stop_logging(HIDE_EVENT);
|
||||
hide_list.clear();
|
||||
hide_enabled = false;
|
||||
close(sockfd);
|
||||
sockfd = -1;
|
||||
pthread_mutex_destroy(&list_lock);
|
||||
LOGD("proc_monitor: terminating\n");
|
||||
pthread_exit(nullptr);
|
||||
@ -124,20 +123,14 @@ void proc_monitor() {
|
||||
term_thread(TERM_THREAD);
|
||||
}
|
||||
|
||||
// Connect to the log daemon
|
||||
sockfd = connect_log_daemon();
|
||||
if (sockfd < 0)
|
||||
pthread_exit(nullptr);
|
||||
write_int(sockfd, HIDE_CONNECT);
|
||||
|
||||
FILE *log_in = fdopen(sockfd, "r");
|
||||
char buf[4096];
|
||||
while (fgets(buf, sizeof(buf), log_in)) {
|
||||
auto &queue = start_logging(HIDE_EVENT);
|
||||
while (true) {
|
||||
char *log;
|
||||
int pid, ppid;
|
||||
struct stat ns, pns;
|
||||
|
||||
if ((log = strchr(buf, '[')) == nullptr)
|
||||
string line = queue.take();
|
||||
if ((log = strchr(&line[0], '[')) == nullptr)
|
||||
continue;
|
||||
|
||||
// Extract pid
|
||||
@ -183,5 +176,4 @@ void proc_monitor() {
|
||||
if (fork_dont_care() == 0)
|
||||
hide_daemon(pid);
|
||||
}
|
||||
pthread_exit(nullptr);
|
||||
}
|
||||
|
80
native/jni/utils/include/BlockingQueue.h
Normal file
80
native/jni/utils/include/BlockingQueue.h
Normal file
@ -0,0 +1,80 @@
|
||||
#pragma once
|
||||
|
||||
#include <pthread.h>
|
||||
#include <deque>
|
||||
|
||||
template<typename T>
|
||||
class BlockingQueue {
|
||||
std::deque<T> deque{};
|
||||
pthread_mutex_t lock;
|
||||
pthread_cond_t cond;
|
||||
public:
|
||||
BlockingQueue() : lock(PTHREAD_MUTEX_INITIALIZER), cond(PTHREAD_COND_INITIALIZER) {}
|
||||
~BlockingQueue();
|
||||
T take();
|
||||
T &front();
|
||||
T &back();
|
||||
void put(const T&);
|
||||
void put(T&&);
|
||||
template< class... Args >
|
||||
void emplace_back(Args&&... args);
|
||||
void clear();
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
BlockingQueue<T>::~BlockingQueue() {
|
||||
pthread_mutex_destroy(&lock);
|
||||
pthread_cond_destroy(&cond);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T BlockingQueue<T>::take() {
|
||||
pthread_mutex_lock(&lock);
|
||||
while (deque.empty())
|
||||
pthread_cond_wait(&cond, &lock);
|
||||
T ret(std::move(deque.front()));
|
||||
deque.pop_front();
|
||||
pthread_mutex_unlock(&lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void BlockingQueue<T>::put(const T &s) {
|
||||
pthread_mutex_lock(&lock);
|
||||
deque.push_back(s);
|
||||
pthread_cond_signal(&cond);
|
||||
pthread_mutex_unlock(&lock);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void BlockingQueue<T>::put(T &&s) {
|
||||
pthread_mutex_lock(&lock);
|
||||
deque.push_back(std::move(s));
|
||||
pthread_cond_signal(&cond);
|
||||
pthread_mutex_unlock(&lock);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T &BlockingQueue<T>::front() {
|
||||
return deque.front();
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T &BlockingQueue<T>::back() {
|
||||
return deque.back();
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
template<class... Args>
|
||||
void BlockingQueue<T>::emplace_back(Args &&... args) {
|
||||
pthread_mutex_lock(&lock);
|
||||
deque.emplace_back(std::forward<Args>(args)...);
|
||||
pthread_cond_signal(&cond);
|
||||
pthread_mutex_unlock(&lock);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void BlockingQueue<T>::clear() {
|
||||
std::deque<T> t;
|
||||
deque.swap(t);
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user