Partition: new class, container for Playlist and PlayerControl
This is the beginning of multi-player support. There will be support for multiple Partition objects in one MPD process.
This commit is contained in:
parent
1a8ef3cdab
commit
d536944beb
@ -262,6 +262,7 @@ src_mpd_SOURCES = \
|
|||||||
src/path.c \
|
src/path.c \
|
||||||
src/Mapper.cxx src/Mapper.hxx \
|
src/Mapper.cxx src/Mapper.hxx \
|
||||||
src/page.c \
|
src/page.c \
|
||||||
|
src/Partition.hxx \
|
||||||
src/Permission.cxx src/Permission.hxx \
|
src/Permission.cxx src/Permission.hxx \
|
||||||
src/PlayerThread.cxx src/PlayerThread.hxx \
|
src/PlayerThread.cxx src/PlayerThread.hxx \
|
||||||
src/PlayerControl.cxx src/PlayerControl.hxx \
|
src/PlayerControl.cxx src/PlayerControl.hxx \
|
||||||
|
@ -20,7 +20,7 @@
|
|||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "Listen.hxx"
|
#include "Listen.hxx"
|
||||||
#include "Main.hxx"
|
#include "Main.hxx"
|
||||||
#include "Playlist.hxx"
|
#include "Partition.hxx"
|
||||||
#include "Client.hxx"
|
#include "Client.hxx"
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
@ -47,7 +47,7 @@ static void
|
|||||||
listen_callback(int fd, const struct sockaddr *address,
|
listen_callback(int fd, const struct sockaddr *address,
|
||||||
size_t address_length, int uid, G_GNUC_UNUSED void *ctx)
|
size_t address_length, int uid, G_GNUC_UNUSED void *ctx)
|
||||||
{
|
{
|
||||||
client_new(g_playlist, global_player_control,
|
client_new(global_partition->playlist, &global_partition->pc,
|
||||||
fd, address, address_length, uid);
|
fd, address, address_length, uid);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
34
src/Main.cxx
34
src/Main.cxx
@ -20,9 +20,7 @@
|
|||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "Main.hxx"
|
#include "Main.hxx"
|
||||||
#include "CommandLine.hxx"
|
#include "CommandLine.hxx"
|
||||||
#include "Playlist.hxx"
|
|
||||||
#include "PlaylistFile.hxx"
|
#include "PlaylistFile.hxx"
|
||||||
#include "PlayerControl.hxx"
|
|
||||||
#include "UpdateGlue.hxx"
|
#include "UpdateGlue.hxx"
|
||||||
#include "MusicChunk.hxx"
|
#include "MusicChunk.hxx"
|
||||||
#include "StateFile.hxx"
|
#include "StateFile.hxx"
|
||||||
@ -35,6 +33,7 @@
|
|||||||
#include "ClientIdle.hxx"
|
#include "ClientIdle.hxx"
|
||||||
#include "Client.hxx"
|
#include "Client.hxx"
|
||||||
#include "AllCommands.hxx"
|
#include "AllCommands.hxx"
|
||||||
|
#include "Partition.hxx"
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#include "daemon.h"
|
#include "daemon.h"
|
||||||
@ -100,7 +99,7 @@ GMainLoop *main_loop;
|
|||||||
|
|
||||||
GCond *main_cond;
|
GCond *main_cond;
|
||||||
|
|
||||||
struct player_control *global_player_control;
|
Partition *global_partition;
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
glue_daemonize_init(const struct options *options, GError **error_r)
|
glue_daemonize_init(const struct options *options, GError **error_r)
|
||||||
@ -231,7 +230,7 @@ glue_state_file_init(GError **error_r)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
state_file_init(path, global_player_control);
|
state_file_init(path, *global_partition);
|
||||||
g_free(path);
|
g_free(path);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@ -306,8 +305,13 @@ initialize_decoder_and_player(void)
|
|||||||
if (buffered_before_play > buffered_chunks)
|
if (buffered_before_play > buffered_chunks)
|
||||||
buffered_before_play = buffered_chunks;
|
buffered_before_play = buffered_chunks;
|
||||||
|
|
||||||
global_player_control = new player_control(buffered_chunks,
|
const unsigned max_length =
|
||||||
buffered_before_play);
|
config_get_positive(CONF_MAX_PLAYLIST_LENGTH,
|
||||||
|
DEFAULT_PLAYLIST_MAX_LENGTH);
|
||||||
|
|
||||||
|
global_partition = new Partition(max_length,
|
||||||
|
buffered_chunks,
|
||||||
|
buffered_before_play);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -414,8 +418,7 @@ int mpd_main(int argc, char *argv[])
|
|||||||
}
|
}
|
||||||
|
|
||||||
initPermissions();
|
initPermissions();
|
||||||
playlist_global_init(config_get_positive(CONF_MAX_PLAYLIST_LENGTH,
|
playlist_global_init();
|
||||||
DEFAULT_PLAYLIST_MAX_LENGTH));
|
|
||||||
spl_global_init();
|
spl_global_init();
|
||||||
#ifdef ENABLE_ARCHIVE
|
#ifdef ENABLE_ARCHIVE
|
||||||
archive_plugin_init_all();
|
archive_plugin_init_all();
|
||||||
@ -438,7 +441,7 @@ int mpd_main(int argc, char *argv[])
|
|||||||
initialize_decoder_and_player();
|
initialize_decoder_and_player();
|
||||||
volume_init();
|
volume_init();
|
||||||
initAudioConfig();
|
initAudioConfig();
|
||||||
audio_output_all_init(global_player_control);
|
audio_output_all_init(&global_partition->pc);
|
||||||
client_manager_init();
|
client_manager_init();
|
||||||
replay_gain_global_init();
|
replay_gain_global_init();
|
||||||
|
|
||||||
@ -464,7 +467,7 @@ int mpd_main(int argc, char *argv[])
|
|||||||
|
|
||||||
initZeroconf();
|
initZeroconf();
|
||||||
|
|
||||||
player_create(global_player_control);
|
player_create(&global_partition->pc);
|
||||||
|
|
||||||
if (create_db) {
|
if (create_db) {
|
||||||
/* the database failed to load: recreate the
|
/* the database failed to load: recreate the
|
||||||
@ -480,7 +483,7 @@ int mpd_main(int argc, char *argv[])
|
|||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
audio_output_all_set_replay_gain_mode(replay_gain_get_real_mode(g_playlist.queue.random));
|
audio_output_all_set_replay_gain_mode(replay_gain_get_real_mode(global_partition->playlist.queue.random));
|
||||||
|
|
||||||
success = config_get_bool(CONF_AUTO_UPDATE, false);
|
success = config_get_bool(CONF_AUTO_UPDATE, false);
|
||||||
#ifdef ENABLE_INOTIFY
|
#ifdef ENABLE_INOTIFY
|
||||||
@ -496,7 +499,7 @@ int mpd_main(int argc, char *argv[])
|
|||||||
|
|
||||||
/* enable all audio outputs (if not already done by
|
/* enable all audio outputs (if not already done by
|
||||||
playlist_state_restore() */
|
playlist_state_restore() */
|
||||||
pc_update_audio(global_player_control);
|
pc_update_audio(&global_partition->pc);
|
||||||
|
|
||||||
#ifdef WIN32
|
#ifdef WIN32
|
||||||
win32_app_started();
|
win32_app_started();
|
||||||
@ -517,12 +520,11 @@ int mpd_main(int argc, char *argv[])
|
|||||||
mpd_inotify_finish();
|
mpd_inotify_finish();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
state_file_finish(global_player_control);
|
state_file_finish(*global_partition);
|
||||||
pc_kill(global_player_control);
|
pc_kill(&global_partition->pc);
|
||||||
finishZeroconf();
|
finishZeroconf();
|
||||||
client_manager_deinit();
|
client_manager_deinit();
|
||||||
listen_global_finish();
|
listen_global_finish();
|
||||||
playlist_global_finish();
|
|
||||||
|
|
||||||
start = clock();
|
start = clock();
|
||||||
DatabaseGlobalDeinit();
|
DatabaseGlobalDeinit();
|
||||||
@ -542,7 +544,7 @@ int mpd_main(int argc, char *argv[])
|
|||||||
volume_finish();
|
volume_finish();
|
||||||
mapper_finish();
|
mapper_finish();
|
||||||
path_global_finish();
|
path_global_finish();
|
||||||
delete global_player_control;
|
delete global_partition;
|
||||||
command_finish();
|
command_finish();
|
||||||
update_global_finish();
|
update_global_finish();
|
||||||
decoder_plugin_deinit_all();
|
decoder_plugin_deinit_all();
|
||||||
|
@ -28,7 +28,7 @@ extern GMainLoop *main_loop;
|
|||||||
|
|
||||||
extern GCond *main_cond;
|
extern GCond *main_cond;
|
||||||
|
|
||||||
extern struct player_control *global_player_control;
|
extern struct Partition *global_partition;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A entry point for application.
|
* A entry point for application.
|
||||||
|
47
src/Partition.hxx
Normal file
47
src/Partition.hxx
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2003-2013 The Music Player Daemon Project
|
||||||
|
* http://www.musicpd.org
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program 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 Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along
|
||||||
|
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef MPD_PARTITION_HXX
|
||||||
|
#define MPD_PARTITION_HXX
|
||||||
|
|
||||||
|
#include "Playlist.hxx"
|
||||||
|
#include "PlayerControl.hxx"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A partition of the Music Player Daemon. It is a separate unit with
|
||||||
|
* a playlist, a player, outputs etc.
|
||||||
|
*/
|
||||||
|
struct Partition {
|
||||||
|
struct playlist playlist;
|
||||||
|
|
||||||
|
player_control pc;
|
||||||
|
|
||||||
|
Partition(unsigned max_length,
|
||||||
|
unsigned buffer_chunks,
|
||||||
|
unsigned buffered_before_play)
|
||||||
|
:pc(buffer_chunks, buffered_before_play) {
|
||||||
|
playlist_init(&playlist, max_length);
|
||||||
|
}
|
||||||
|
|
||||||
|
~Partition() {
|
||||||
|
playlist_finish(&playlist);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
@ -70,14 +70,8 @@ struct playlist {
|
|||||||
int queued;
|
int queued;
|
||||||
};
|
};
|
||||||
|
|
||||||
/** the global playlist object */
|
|
||||||
extern struct playlist g_playlist;
|
|
||||||
|
|
||||||
void
|
void
|
||||||
playlist_global_init(unsigned max_length);
|
playlist_global_init();
|
||||||
|
|
||||||
void
|
|
||||||
playlist_global_finish(void);
|
|
||||||
|
|
||||||
void
|
void
|
||||||
playlist_init(struct playlist *playlist, unsigned max_length);
|
playlist_init(struct playlist *playlist, unsigned max_length);
|
||||||
|
@ -25,36 +25,28 @@
|
|||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "Playlist.hxx"
|
#include "Playlist.hxx"
|
||||||
#include "Main.hxx"
|
#include "Main.hxx"
|
||||||
|
#include "Partition.hxx"
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#include "event_pipe.h"
|
#include "event_pipe.h"
|
||||||
}
|
}
|
||||||
|
|
||||||
struct playlist g_playlist;
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
playlist_tag_event(void)
|
playlist_tag_event(void)
|
||||||
{
|
{
|
||||||
playlist_tag_changed(&g_playlist);
|
playlist_tag_changed(&global_partition->playlist);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
playlist_event(void)
|
playlist_event(void)
|
||||||
{
|
{
|
||||||
playlist_sync(&g_playlist, global_player_control);
|
playlist_sync(&global_partition->playlist,
|
||||||
|
&global_partition->pc);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
playlist_global_init(unsigned max_length)
|
playlist_global_init()
|
||||||
{
|
{
|
||||||
playlist_init(&g_playlist, max_length);
|
|
||||||
|
|
||||||
event_pipe_register(PIPE_EVENT_TAG, playlist_tag_event);
|
event_pipe_register(PIPE_EVENT_TAG, playlist_tag_event);
|
||||||
event_pipe_register(PIPE_EVENT_PLAYLIST, playlist_event);
|
event_pipe_register(PIPE_EVENT_PLAYLIST, playlist_event);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
playlist_global_finish(void)
|
|
||||||
{
|
|
||||||
playlist_finish(&g_playlist);
|
|
||||||
}
|
|
||||||
|
@ -20,9 +20,9 @@
|
|||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "StateFile.hxx"
|
#include "StateFile.hxx"
|
||||||
#include "OutputState.hxx"
|
#include "OutputState.hxx"
|
||||||
#include "Playlist.hxx"
|
|
||||||
#include "PlaylistState.hxx"
|
#include "PlaylistState.hxx"
|
||||||
#include "TextFile.hxx"
|
#include "TextFile.hxx"
|
||||||
|
#include "Partition.hxx"
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#include "volume.h"
|
#include "volume.h"
|
||||||
@ -49,7 +49,7 @@ static unsigned prev_volume_version, prev_output_version,
|
|||||||
prev_playlist_version;
|
prev_playlist_version;
|
||||||
|
|
||||||
static void
|
static void
|
||||||
state_file_write(struct player_control *pc)
|
state_file_write(Partition &partition)
|
||||||
{
|
{
|
||||||
FILE *fp;
|
FILE *fp;
|
||||||
|
|
||||||
@ -66,17 +66,18 @@ state_file_write(struct player_control *pc)
|
|||||||
|
|
||||||
save_sw_volume_state(fp);
|
save_sw_volume_state(fp);
|
||||||
audio_output_state_save(fp);
|
audio_output_state_save(fp);
|
||||||
playlist_state_save(fp, &g_playlist, pc);
|
playlist_state_save(fp, &partition.playlist, &partition.pc);
|
||||||
|
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
|
|
||||||
prev_volume_version = sw_volume_state_get_hash();
|
prev_volume_version = sw_volume_state_get_hash();
|
||||||
prev_output_version = audio_output_state_get_version();
|
prev_output_version = audio_output_state_get_version();
|
||||||
prev_playlist_version = playlist_state_get_hash(&g_playlist, pc);
|
prev_playlist_version = playlist_state_get_hash(&partition.playlist,
|
||||||
|
&partition.pc);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
state_file_read(struct player_control *pc)
|
state_file_read(Partition &partition)
|
||||||
{
|
{
|
||||||
bool success;
|
bool success;
|
||||||
|
|
||||||
@ -95,14 +96,16 @@ state_file_read(struct player_control *pc)
|
|||||||
while ((line = file.ReadLine()) != NULL) {
|
while ((line = file.ReadLine()) != NULL) {
|
||||||
success = read_sw_volume_state(line) ||
|
success = read_sw_volume_state(line) ||
|
||||||
audio_output_state_read(line) ||
|
audio_output_state_read(line) ||
|
||||||
playlist_state_restore(line, file, &g_playlist, pc);
|
playlist_state_restore(line, file, &partition.playlist,
|
||||||
|
&partition.pc);
|
||||||
if (!success)
|
if (!success)
|
||||||
g_warning("Unrecognized line in state file: %s", line);
|
g_warning("Unrecognized line in state file: %s", line);
|
||||||
}
|
}
|
||||||
|
|
||||||
prev_volume_version = sw_volume_state_get_hash();
|
prev_volume_version = sw_volume_state_get_hash();
|
||||||
prev_output_version = audio_output_state_get_version();
|
prev_output_version = audio_output_state_get_version();
|
||||||
prev_playlist_version = playlist_state_get_hash(&g_playlist, pc);
|
prev_playlist_version = playlist_state_get_hash(&partition.playlist,
|
||||||
|
&partition.pc);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -112,21 +115,22 @@ state_file_read(struct player_control *pc)
|
|||||||
static gboolean
|
static gboolean
|
||||||
timer_save_state_file(gpointer data)
|
timer_save_state_file(gpointer data)
|
||||||
{
|
{
|
||||||
struct player_control *pc = (struct player_control *)data;
|
Partition &partition = *(Partition *)data;
|
||||||
|
|
||||||
if (prev_volume_version == sw_volume_state_get_hash() &&
|
if (prev_volume_version == sw_volume_state_get_hash() &&
|
||||||
prev_output_version == audio_output_state_get_version() &&
|
prev_output_version == audio_output_state_get_version() &&
|
||||||
prev_playlist_version == playlist_state_get_hash(&g_playlist, pc))
|
prev_playlist_version == playlist_state_get_hash(&partition.playlist,
|
||||||
|
&partition.pc))
|
||||||
/* nothing has changed - don't save the state file,
|
/* nothing has changed - don't save the state file,
|
||||||
don't spin up the hard disk */
|
don't spin up the hard disk */
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
state_file_write(pc);
|
state_file_write(partition);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
state_file_init(const char *path, struct player_control *pc)
|
state_file_init(const char *path, Partition &partition)
|
||||||
{
|
{
|
||||||
assert(state_file_path == NULL);
|
assert(state_file_path == NULL);
|
||||||
|
|
||||||
@ -134,15 +138,15 @@ state_file_init(const char *path, struct player_control *pc)
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
state_file_path = g_strdup(path);
|
state_file_path = g_strdup(path);
|
||||||
state_file_read(pc);
|
state_file_read(partition);
|
||||||
|
|
||||||
save_state_source_id = g_timeout_add_seconds(5 * 60,
|
save_state_source_id = g_timeout_add_seconds(5 * 60,
|
||||||
timer_save_state_file,
|
timer_save_state_file,
|
||||||
pc);
|
&partition);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
state_file_finish(struct player_control *pc)
|
state_file_finish(Partition &partition)
|
||||||
{
|
{
|
||||||
if (state_file_path == NULL)
|
if (state_file_path == NULL)
|
||||||
/* no state file configured, no cleanup required */
|
/* no state file configured, no cleanup required */
|
||||||
@ -151,7 +155,7 @@ state_file_finish(struct player_control *pc)
|
|||||||
if (save_state_source_id != 0)
|
if (save_state_source_id != 0)
|
||||||
g_source_remove(save_state_source_id);
|
g_source_remove(save_state_source_id);
|
||||||
|
|
||||||
state_file_write(pc);
|
state_file_write(partition);
|
||||||
|
|
||||||
g_free(state_file_path);
|
g_free(state_file_path);
|
||||||
}
|
}
|
||||||
|
@ -20,13 +20,13 @@
|
|||||||
#ifndef MPD_STATE_FILE_HXX
|
#ifndef MPD_STATE_FILE_HXX
|
||||||
#define MPD_STATE_FILE_HXX
|
#define MPD_STATE_FILE_HXX
|
||||||
|
|
||||||
struct player_control;
|
struct Partition;
|
||||||
|
|
||||||
void
|
void
|
||||||
state_file_init(const char *path, struct player_control *pc);
|
state_file_init(const char *path, Partition &partition);
|
||||||
|
|
||||||
void
|
void
|
||||||
state_file_finish(struct player_control *pc);
|
state_file_finish(Partition &partition);
|
||||||
|
|
||||||
void write_state_file(void);
|
void write_state_file(void);
|
||||||
|
|
||||||
|
@ -24,7 +24,6 @@
|
|||||||
#include "UpdateRemove.hxx"
|
#include "UpdateRemove.hxx"
|
||||||
#include "Mapper.hxx"
|
#include "Mapper.hxx"
|
||||||
#include "DatabaseSimple.hxx"
|
#include "DatabaseSimple.hxx"
|
||||||
#include "Playlist.hxx"
|
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#include "event_pipe.h"
|
#include "event_pipe.h"
|
||||||
@ -33,6 +32,7 @@ extern "C" {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#include "Main.hxx"
|
#include "Main.hxx"
|
||||||
|
#include "Partition.hxx"
|
||||||
#include "mpd_error.h"
|
#include "mpd_error.h"
|
||||||
|
|
||||||
#include <glib.h>
|
#include <glib.h>
|
||||||
@ -155,7 +155,7 @@ static void update_finished_event(void)
|
|||||||
|
|
||||||
if (modified) {
|
if (modified) {
|
||||||
/* send "idle" events */
|
/* send "idle" events */
|
||||||
playlist_increment_version_all(&g_playlist);
|
playlist_increment_version_all(&global_partition->playlist);
|
||||||
idle_add(IDLE_DATABASE);
|
idle_add(IDLE_DATABASE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -20,6 +20,7 @@
|
|||||||
#include "config.h" /* must be first for large file support */
|
#include "config.h" /* must be first for large file support */
|
||||||
#include "UpdateRemove.hxx"
|
#include "UpdateRemove.hxx"
|
||||||
#include "Playlist.hxx"
|
#include "Playlist.hxx"
|
||||||
|
#include "Partition.hxx"
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#include "event_pipe.h"
|
#include "event_pipe.h"
|
||||||
@ -63,7 +64,9 @@ song_remove_event(void)
|
|||||||
sticker_song_delete(removed_song);
|
sticker_song_delete(removed_song);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
playlist_delete_song(&g_playlist, global_player_control, removed_song);
|
playlist_delete_song(&global_partition->playlist,
|
||||||
|
&global_partition->pc,
|
||||||
|
removed_song);
|
||||||
|
|
||||||
/* clear "removed_song" and send signal to update thread */
|
/* clear "removed_song" and send signal to update thread */
|
||||||
g_mutex_lock(remove_mutex);
|
g_mutex_lock(remove_mutex);
|
||||||
|
Loading…
Reference in New Issue
Block a user