Cleaned up, fixed and robustified semaphore and signal related code
This commit is contained in:
parent
ee9b076b76
commit
24006648f9
7 changed files with 165 additions and 131 deletions
|
@ -401,7 +401,7 @@ void Util::Config::activate() {
|
||||||
struct sigaction cur_action;
|
struct sigaction cur_action;
|
||||||
new_action.sa_sigaction = signal_handler;
|
new_action.sa_sigaction = signal_handler;
|
||||||
sigemptyset(&new_action.sa_mask);
|
sigemptyset(&new_action.sa_mask);
|
||||||
new_action.sa_flags = 0;
|
new_action.sa_flags = SA_SIGINFO;
|
||||||
sigaction(SIGINT, &new_action, NULL);
|
sigaction(SIGINT, &new_action, NULL);
|
||||||
sigaction(SIGHUP, &new_action, NULL);
|
sigaction(SIGHUP, &new_action, NULL);
|
||||||
sigaction(SIGTERM, &new_action, NULL);
|
sigaction(SIGTERM, &new_action, NULL);
|
||||||
|
@ -423,6 +423,10 @@ void Util::Config::signal_handler(int signum, siginfo_t * sigInfo, void * ignore
|
||||||
case SIGHUP:
|
case SIGHUP:
|
||||||
case SIGTERM:
|
case SIGTERM:
|
||||||
if (serv_sock_pointer){serv_sock_pointer->close();}
|
if (serv_sock_pointer){serv_sock_pointer->close();}
|
||||||
|
#if DEBUG >= DLVL_DEVEL
|
||||||
|
static int ctr = 0;
|
||||||
|
if (!is_active && ++ctr > 4){BACKTRACE;}
|
||||||
|
#endif
|
||||||
is_active = false;
|
is_active = false;
|
||||||
default:
|
default:
|
||||||
switch (sigInfo->si_code){
|
switch (sigInfo->si_code){
|
||||||
|
|
|
@ -93,6 +93,7 @@ namespace IPC {
|
||||||
#else
|
#else
|
||||||
mySem = SEM_FAILED;
|
mySem = SEM_FAILED;
|
||||||
#endif
|
#endif
|
||||||
|
isLocked = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
///\brief Constructs a named semaphore
|
///\brief Constructs a named semaphore
|
||||||
|
@ -106,6 +107,7 @@ namespace IPC {
|
||||||
#else
|
#else
|
||||||
mySem = SEM_FAILED;
|
mySem = SEM_FAILED;
|
||||||
#endif
|
#endif
|
||||||
|
isLocked = false;
|
||||||
open(name, oflag, mode, value, noWait);
|
open(name, oflag, mode, value, noWait);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -178,10 +180,10 @@ namespace IPC {
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
if (!(*this)) {
|
if (*this) {
|
||||||
}
|
|
||||||
myName = (char *)name;
|
myName = (char *)name;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
///\brief Returns the current value of the semaphore
|
///\brief Returns the current value of the semaphore
|
||||||
int semaphore::getVal() const {
|
int semaphore::getVal() const {
|
||||||
|
@ -197,12 +199,20 @@ namespace IPC {
|
||||||
|
|
||||||
///\brief Posts to the semaphore, increases its value by one
|
///\brief Posts to the semaphore, increases its value by one
|
||||||
void semaphore::post() {
|
void semaphore::post() {
|
||||||
|
if (!*this || !isLocked){
|
||||||
|
FAIL_MSG("Attempted to unlock a non-locked semaphore: '%s'!", myName.c_str());
|
||||||
|
#if DEBUG >= DLVL_DEVEL
|
||||||
|
BACKTRACE;
|
||||||
|
#endif
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (*this) {
|
if (*this) {
|
||||||
#if defined(__CYGWIN__) || defined(_WIN32)
|
#if defined(__CYGWIN__) || defined(_WIN32)
|
||||||
ReleaseMutex(mySem);
|
ReleaseMutex(mySem);
|
||||||
#else
|
#else
|
||||||
sem_post(mySem);
|
sem_post(mySem);
|
||||||
#endif
|
#endif
|
||||||
|
isLocked = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -217,6 +227,7 @@ namespace IPC {
|
||||||
tmp = sem_wait(mySem);
|
tmp = sem_wait(mySem);
|
||||||
} while (tmp == -1 && errno == EINTR);
|
} while (tmp == -1 && errno == EINTR);
|
||||||
#endif
|
#endif
|
||||||
|
isLocked = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -235,7 +246,7 @@ namespace IPC {
|
||||||
result = sem_trywait(mySem);
|
result = sem_trywait(mySem);
|
||||||
} while (result == -1 && errno == EINTR);
|
} while (result == -1 && errno == EINTR);
|
||||||
#endif
|
#endif
|
||||||
return (result == 0);
|
return isLocked = (result == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
///\brief Tries to wait for the semaphore for a single second, returns true if successful, false otherwise
|
///\brief Tries to wait for the semaphore for a single second, returns true if successful, false otherwise
|
||||||
|
@ -254,6 +265,7 @@ namespace IPC {
|
||||||
long long unsigned int timeout = now + 1e6;
|
long long unsigned int timeout = now + 1e6;
|
||||||
while (now < timeout) {
|
while (now < timeout) {
|
||||||
if (0 == sem_trywait(mySem)) {
|
if (0 == sem_trywait(mySem)) {
|
||||||
|
isLocked = true;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
usleep(100e3);
|
usleep(100e3);
|
||||||
|
@ -266,12 +278,28 @@ namespace IPC {
|
||||||
wt.tv_nsec = 0;
|
wt.tv_nsec = 0;
|
||||||
result = sem_timedwait(mySem, &wt);
|
result = sem_timedwait(mySem, &wt);
|
||||||
#endif
|
#endif
|
||||||
return (result == 0);
|
return isLocked = (result == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
///\brief Closes the currently opened semaphore
|
///\brief Closes the currently opened semaphore
|
||||||
void semaphore::close() {
|
void semaphore::close() {
|
||||||
if (*this) {
|
if (*this) {
|
||||||
|
if (isLocked){post();}
|
||||||
|
#if defined(__CYGWIN__) || defined(_WIN32)
|
||||||
|
CloseHandle(mySem);
|
||||||
|
mySem = 0;
|
||||||
|
#else
|
||||||
|
sem_close(mySem);
|
||||||
|
mySem = SEM_FAILED;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
myName.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Closes the semaphore, without unlocking it first.
|
||||||
|
/// Intended to be called from forked child processes, to drop the reference to the semaphore.
|
||||||
|
void semaphore::abandon() {
|
||||||
|
if (*this) {
|
||||||
#if defined(__CYGWIN__) || defined(_WIN32)
|
#if defined(__CYGWIN__) || defined(_WIN32)
|
||||||
CloseHandle(mySem);
|
CloseHandle(mySem);
|
||||||
mySem = 0;
|
mySem = 0;
|
||||||
|
@ -280,19 +308,28 @@ namespace IPC {
|
||||||
mySem = SEM_FAILED;
|
mySem = SEM_FAILED;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
///\brief Unlinks the previously opened semaphore
|
|
||||||
void semaphore::unlink() {
|
|
||||||
close();
|
|
||||||
#if !defined(__CYGWIN__) && !defined(_WIN32)
|
|
||||||
if (myName.size()) {
|
|
||||||
sem_unlink(myName.c_str());
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
myName.clear();
|
myName.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Unlinks the previously opened semaphore, closing it (if open) in the process.
|
||||||
|
void semaphore::unlink() {
|
||||||
|
#if defined(__CYGWIN__) || defined(_WIN32)
|
||||||
|
if (isLocked){post();}
|
||||||
|
#endif
|
||||||
|
#if !defined(__CYGWIN__) && !defined(_WIN32)
|
||||||
|
if (myName.size()){sem_unlink(myName.c_str());}
|
||||||
|
#endif
|
||||||
|
if (*this) {
|
||||||
|
#if defined(__CYGWIN__) || defined(_WIN32)
|
||||||
|
CloseHandle(mySem);
|
||||||
|
mySem = 0;
|
||||||
|
#else
|
||||||
|
sem_close(mySem);
|
||||||
|
mySem = SEM_FAILED;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
myName.clear();
|
||||||
|
}
|
||||||
|
|
||||||
#if defined(__CYGWIN__) || defined(_WIN32)
|
#if defined(__CYGWIN__) || defined(_WIN32)
|
||||||
SECURITY_ATTRIBUTES semaphore::getSecurityAttributes() {
|
SECURITY_ATTRIBUTES semaphore::getSecurityAttributes() {
|
||||||
|
@ -368,7 +405,7 @@ namespace IPC {
|
||||||
|
|
||||||
///\brief Unmaps a shared page if allowed
|
///\brief Unmaps a shared page if allowed
|
||||||
void sharedPage::unmap() {
|
void sharedPage::unmap() {
|
||||||
if (mapped && len) {
|
if (mapped) {
|
||||||
#if defined(__CYGWIN__) || defined(_WIN32)
|
#if defined(__CYGWIN__) || defined(_WIN32)
|
||||||
//under Cygwin, the mapped location is shifted by 4 to contain the page size.
|
//under Cygwin, the mapped location is shifted by 4 to contain the page size.
|
||||||
UnmapViewOfFile(mapped - 4);
|
UnmapViewOfFile(mapped - 4);
|
||||||
|
@ -795,26 +832,19 @@ namespace IPC {
|
||||||
baseName = "/" + name;
|
baseName = "/" + name;
|
||||||
payLen = len;
|
payLen = len;
|
||||||
hasCounter = withCounter;
|
hasCounter = withCounter;
|
||||||
mySemaphore.open(baseName.c_str(), O_CREAT | O_EXCL | O_RDWR, ACCESSPERMS, 1);
|
|
||||||
if (!mySemaphore) {
|
|
||||||
mySemaphore.open(baseName.c_str(), O_CREAT | O_RDWR, ACCESSPERMS, 1);
|
mySemaphore.open(baseName.c_str(), O_CREAT | O_RDWR, ACCESSPERMS, 1);
|
||||||
}
|
|
||||||
if (!mySemaphore) {
|
if (!mySemaphore) {
|
||||||
DEBUG_MSG(DLVL_FAIL, "Creating semaphore failed: %s", strerror(errno));
|
DEBUG_MSG(DLVL_FAIL, "Creating semaphore failed: %s", strerror(errno));
|
||||||
return;
|
return;
|
||||||
}
|
}else{
|
||||||
if (!mySemaphore.tryWaitOneSecond()){
|
|
||||||
WARN_MSG("Force unlocking sharedServer semaphore to prevent deadlock");
|
|
||||||
}
|
|
||||||
mySemaphore.post();
|
|
||||||
semGuard tmpGuard(&mySemaphore);
|
semGuard tmpGuard(&mySemaphore);
|
||||||
amount = 0;
|
amount = 0;
|
||||||
newPage();
|
newPage();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
///\brief The deconstructor
|
///\brief The deconstructor
|
||||||
sharedServer::~sharedServer() {
|
sharedServer::~sharedServer() {
|
||||||
mySemaphore.close();
|
|
||||||
mySemaphore.unlink();
|
mySemaphore.unlink();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1251,7 +1281,7 @@ namespace IPC {
|
||||||
if (!hasCounter) {
|
if (!hasCounter) {
|
||||||
return (myPage.mapped != 0);
|
return (myPage.mapped != 0);
|
||||||
}
|
}
|
||||||
if (myPage.mapped){
|
if (myPage.mapped && offsetOnPage >= 0){
|
||||||
return (myPage.mapped[offsetOnPage] & 0x7F) < 60;
|
return (myPage.mapped[offsetOnPage] & 0x7F) < 60;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -75,6 +75,7 @@ namespace IPC {
|
||||||
bool tryWait();
|
bool tryWait();
|
||||||
bool tryWaitOneSecond();
|
bool tryWaitOneSecond();
|
||||||
void close();
|
void close();
|
||||||
|
void abandon();
|
||||||
void unlink();
|
void unlink();
|
||||||
private:
|
private:
|
||||||
#if defined(__CYGWIN__) || defined(_WIN32)
|
#if defined(__CYGWIN__) || defined(_WIN32)
|
||||||
|
@ -84,6 +85,7 @@ namespace IPC {
|
||||||
#else
|
#else
|
||||||
sem_t * mySem;
|
sem_t * mySem;
|
||||||
#endif
|
#endif
|
||||||
|
bool isLocked;
|
||||||
std::string myName;
|
std::string myName;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -83,7 +83,8 @@ void statusMonitor(void *np){
|
||||||
WARN_MSG("Configuration semaphore was stuck. Force-unlocking it and re-writing config.");
|
WARN_MSG("Configuration semaphore was stuck. Force-unlocking it and re-writing config.");
|
||||||
changed = true;
|
changed = true;
|
||||||
}
|
}
|
||||||
configLock.post();
|
configLock.unlink();
|
||||||
|
configLock.open(SEM_CONF, O_CREAT | O_RDWR, ACCESSPERMS, 1);
|
||||||
if (changed || Controller::configChanged){
|
if (changed || Controller::configChanged){
|
||||||
Controller::writeConfig();
|
Controller::writeConfig();
|
||||||
Controller::configChanged = false;
|
Controller::configChanged = false;
|
||||||
|
|
|
@ -109,12 +109,20 @@ namespace Mist {
|
||||||
}
|
}
|
||||||
|
|
||||||
IPC::semaphore playerLock;
|
IPC::semaphore playerLock;
|
||||||
if (needsLock() && streamName.size()){
|
IPC::semaphore pullLock;
|
||||||
|
|
||||||
|
//If we're not converting, we might need a lock.
|
||||||
|
if (streamName.size()){
|
||||||
|
if (needsLock()){
|
||||||
|
//needsLock() == true means this input is the sole responsible input for a stream
|
||||||
|
//That means it's MistInBuffer for live, or the actual input binary for VoD
|
||||||
|
//For these cases, we lock the SEM_INPUT semaphore.
|
||||||
char semName[NAME_BUFFER_SIZE];
|
char semName[NAME_BUFFER_SIZE];
|
||||||
snprintf(semName, NAME_BUFFER_SIZE, SEM_INPUT, streamName.c_str());
|
snprintf(semName, NAME_BUFFER_SIZE, SEM_INPUT, streamName.c_str());
|
||||||
playerLock.open(semName, O_CREAT | O_RDWR, ACCESSPERMS, 1);
|
playerLock.open(semName, O_CREAT | O_RDWR, ACCESSPERMS, 1);
|
||||||
if (!playerLock.tryWait()){
|
if (!playerLock.tryWait()){
|
||||||
DEBUG_MSG(DLVL_DEVEL, "A player for stream %s is already running", streamName.c_str());
|
INFO_MSG("A player for stream %s is already running", streamName.c_str());
|
||||||
|
playerLock.close();
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
char pageName[NAME_BUFFER_SIZE];
|
char pageName[NAME_BUFFER_SIZE];
|
||||||
|
@ -123,27 +131,55 @@ namespace Mist {
|
||||||
if (streamStatus){streamStatus.mapped[0] = STRMSTAT_INIT;}
|
if (streamStatus){streamStatus.mapped[0] = STRMSTAT_INIT;}
|
||||||
streamStatus.master = false;
|
streamStatus.master = false;
|
||||||
streamStatus.close();
|
streamStatus.close();
|
||||||
|
}else{
|
||||||
|
//needsLock() == false means this binary will itself start the sole responsible input
|
||||||
|
//So, we definitely do NOT lock SEM_INPUT, since the child process will do that later.
|
||||||
|
//However, most of these processes are singular, meaning they expect to be the only source of data.
|
||||||
|
//To prevent multiple singular processes starting, we use the MstPull semaphore if this input
|
||||||
|
//is indeed a singular input type.
|
||||||
|
if (isSingular()){
|
||||||
|
pullLock.open(std::string("/MstPull_" + streamName).c_str(), O_CREAT | O_RDWR, ACCESSPERMS, 1);
|
||||||
|
if (!pullLock){
|
||||||
|
FAIL_MSG("Could not open pull lock for stream '%s' - aborting!", streamName.c_str());
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
|
if (!pullLock.tryWait()){
|
||||||
|
WARN_MSG("A pull process for stream %s is already running", streamName.c_str());
|
||||||
|
pullLock.close();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
config->activate();
|
config->activate();
|
||||||
uint64_t reTimer = 0;
|
uint64_t reTimer = 0;
|
||||||
while (config->is_active){
|
while (config->is_active){
|
||||||
pid_t pid = fork();
|
pid_t pid = fork();
|
||||||
if (pid == 0){
|
if (pid == 0){
|
||||||
|
if (playerLock){
|
||||||
//Re-init streamStatus, previously closed
|
//Re-init streamStatus, previously closed
|
||||||
char pageName[NAME_BUFFER_SIZE];
|
char pageName[NAME_BUFFER_SIZE];
|
||||||
snprintf(pageName, NAME_BUFFER_SIZE, SHM_STREAM_STATE, streamName.c_str());
|
snprintf(pageName, NAME_BUFFER_SIZE, SHM_STREAM_STATE, streamName.c_str());
|
||||||
streamStatus.init(pageName, 1, true, false);
|
streamStatus.init(pageName, 1, true, false);
|
||||||
streamStatus.master = false;
|
streamStatus.master = false;
|
||||||
if (streamStatus){streamStatus.mapped[0] = STRMSTAT_INIT;}
|
if (streamStatus){streamStatus.mapped[0] = STRMSTAT_INIT;}
|
||||||
if (needsLock()){playerLock.close();}
|
}
|
||||||
|
//Abandon all semaphores, ye who enter here.
|
||||||
|
playerLock.abandon();
|
||||||
|
pullLock.abandon();
|
||||||
if (!preRun()){return 0;}
|
if (!preRun()){return 0;}
|
||||||
return run();
|
return run();
|
||||||
}
|
}
|
||||||
if (pid == -1){
|
if (pid == -1){
|
||||||
FAIL_MSG("Unable to spawn input process");
|
FAIL_MSG("Unable to spawn input process");
|
||||||
if (needsLock()){playerLock.post();}
|
//We failed. Release the kra... semaphores!
|
||||||
|
//post() contains an is-open check already, no need to double-check.
|
||||||
|
playerLock.unlink();
|
||||||
|
pullLock.unlink();
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
|
HIGH_MSG("Waiting for child for stream %s", streamName.c_str());
|
||||||
//wait for the process to exit
|
//wait for the process to exit
|
||||||
int status;
|
int status;
|
||||||
while (waitpid(pid, &status, 0) != pid && errno == EINTR){
|
while (waitpid(pid, &status, 0) != pid && errno == EINTR){
|
||||||
|
@ -153,35 +189,38 @@ namespace Mist {
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
HIGH_MSG("Done waiting for child for stream %s", streamName.c_str());
|
||||||
//if the exit was clean, don't restart it
|
//if the exit was clean, don't restart it
|
||||||
if (WIFEXITED(status) && (WEXITSTATUS(status) == 0)){
|
if (WIFEXITED(status) && (WEXITSTATUS(status) == 0)){
|
||||||
INFO_MSG("Input for stream %s shut down cleanly", streamName.c_str());
|
INFO_MSG("Input for stream %s shut down cleanly", streamName.c_str());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
if (playerLock){
|
||||||
char pageName[NAME_BUFFER_SIZE];
|
char pageName[NAME_BUFFER_SIZE];
|
||||||
snprintf(pageName, NAME_BUFFER_SIZE, SHM_STREAM_STATE, streamName.c_str());
|
snprintf(pageName, NAME_BUFFER_SIZE, SHM_STREAM_STATE, streamName.c_str());
|
||||||
streamStatus.init(pageName, 1, true, false);
|
streamStatus.init(pageName, 1, true, false);
|
||||||
if (streamStatus){streamStatus.mapped[0] = STRMSTAT_INVALID;}
|
if (streamStatus){streamStatus.mapped[0] = STRMSTAT_INVALID;}
|
||||||
|
}
|
||||||
#if DEBUG >= DLVL_DEVEL
|
#if DEBUG >= DLVL_DEVEL
|
||||||
WARN_MSG("Aborting autoclean; this is a development build.");
|
WARN_MSG("Input for stream %s uncleanly shut down! Aborting restart; this is a development build.", streamName.c_str());
|
||||||
INFO_MSG("Input for stream %s uncleanly shut down! Aborting restart; this is a development build.", streamName.c_str());
|
|
||||||
break;
|
break;
|
||||||
#else
|
#else
|
||||||
|
WARN_MSG("Input for stream %s uncleanly shut down! Restarting...", streamName.c_str());
|
||||||
onCrash();
|
onCrash();
|
||||||
INFO_MSG("Input for stream %s uncleanly shut down! Restarting...", streamName.c_str());
|
|
||||||
Util::wait(reTimer);
|
Util::wait(reTimer);
|
||||||
reTimer += 1000;
|
reTimer += 1000;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
if (needsLock()){
|
|
||||||
playerLock.post();
|
if (playerLock){
|
||||||
playerLock.unlink();
|
playerLock.unlink();
|
||||||
playerLock.close();
|
|
||||||
}
|
|
||||||
char pageName[NAME_BUFFER_SIZE];
|
char pageName[NAME_BUFFER_SIZE];
|
||||||
snprintf(pageName, NAME_BUFFER_SIZE, SHM_STREAM_STATE, streamName.c_str());
|
snprintf(pageName, NAME_BUFFER_SIZE, SHM_STREAM_STATE, streamName.c_str());
|
||||||
streamStatus.init(pageName, 1, true, false);
|
streamStatus.init(pageName, 1, true, false);
|
||||||
streamStatus.close();
|
streamStatus.close();
|
||||||
|
}
|
||||||
|
pullLock.unlink();
|
||||||
|
|
||||||
HIGH_MSG("Angel process for %s exiting", streamName.c_str());
|
HIGH_MSG("Angel process for %s exiting", streamName.c_str());
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -207,29 +246,21 @@ namespace Mist {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!streamName.size()) {
|
if (!streamName.size()) {
|
||||||
|
//If we don't have a stream name, that means we're in stand-alone conversion mode.
|
||||||
MEDIUM_MSG("Starting convert");
|
MEDIUM_MSG("Starting convert");
|
||||||
convert();
|
convert();
|
||||||
} else if (!needsLock()) {
|
} else if (!needsLock()) {
|
||||||
|
//We have a name and aren't the sole process. That means we're streaming live data to a buffer.
|
||||||
MEDIUM_MSG("Starting stream");
|
MEDIUM_MSG("Starting stream");
|
||||||
stream();
|
stream();
|
||||||
}else{
|
}else{
|
||||||
|
//We are the sole process and have a name. That means this is a Buffer or VoD input.
|
||||||
MEDIUM_MSG("Starting serve");
|
MEDIUM_MSG("Starting serve");
|
||||||
serve();
|
serve();
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Default crash handler, cleans up Pull semaphore on crashes
|
|
||||||
void Input::onCrash(){
|
|
||||||
if (streamName.size() && !needsLock()) {
|
|
||||||
//we have a Pull semaphore to clean up, do it
|
|
||||||
IPC::semaphore pullLock;
|
|
||||||
pullLock.open(std::string("/MstPull_" + streamName).c_str(), O_CREAT | O_RDWR, ACCESSPERMS, 1);
|
|
||||||
pullLock.close();
|
|
||||||
pullLock.unlink();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Input::convert() {
|
void Input::convert() {
|
||||||
//check filename for no -
|
//check filename for no -
|
||||||
if (config->getString("output") != "-"){
|
if (config->getString("output") != "-"){
|
||||||
|
@ -296,7 +327,7 @@ namespace Mist {
|
||||||
userPage.init(userPageName, PLAY_EX_SIZE, true);
|
userPage.init(userPageName, PLAY_EX_SIZE, true);
|
||||||
if (streamStatus){streamStatus.mapped[0] = STRMSTAT_READY;}
|
if (streamStatus){streamStatus.mapped[0] = STRMSTAT_READY;}
|
||||||
|
|
||||||
DEBUG_MSG(DLVL_DEVEL, "Input for stream %s started", streamName.c_str());
|
INFO_MSG("Input for stream %s started", streamName.c_str());
|
||||||
activityCounter = Util::bootSecs();
|
activityCounter = Util::bootSecs();
|
||||||
//main serve loop
|
//main serve loop
|
||||||
while (keepRunning()) {
|
while (keepRunning()) {
|
||||||
|
@ -321,7 +352,7 @@ namespace Mist {
|
||||||
if (streamStatus){streamStatus.mapped[0] = STRMSTAT_SHUTDOWN;}
|
if (streamStatus){streamStatus.mapped[0] = STRMSTAT_SHUTDOWN;}
|
||||||
config->is_active = false;
|
config->is_active = false;
|
||||||
finish();
|
finish();
|
||||||
DEBUG_MSG(DLVL_DEVEL, "Input for stream %s closing clean", streamName.c_str());
|
INFO_MSG("Input for stream %s closing clean", streamName.c_str());
|
||||||
userPage.finishEach();
|
userPage.finishEach();
|
||||||
//end player functionality
|
//end player functionality
|
||||||
}
|
}
|
||||||
|
@ -352,28 +383,11 @@ namespace Mist {
|
||||||
/// - if there are tracks, register as a non-viewer on the user page of the buffer
|
/// - if there are tracks, register as a non-viewer on the user page of the buffer
|
||||||
/// - call getNext() in a loop, buffering packets
|
/// - call getNext() in a loop, buffering packets
|
||||||
void Input::stream(){
|
void Input::stream(){
|
||||||
IPC::semaphore pullLock;
|
|
||||||
if(isSingular()){
|
|
||||||
pullLock.open(std::string("/MstPull_" + streamName).c_str(), O_CREAT | O_RDWR, ACCESSPERMS, 1);
|
|
||||||
if (!pullLock){
|
|
||||||
FAIL_MSG("Could not open pull lock for stream '%s' - aborting!", streamName.c_str());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!pullLock.tryWait()){
|
|
||||||
WARN_MSG("A pull process for stream %s is already running", streamName.c_str());
|
|
||||||
pullLock.close();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Util::streamAlive(streamName)){
|
if (Util::streamAlive(streamName)){
|
||||||
pullLock.post();
|
|
||||||
pullLock.close();
|
|
||||||
pullLock.unlink();
|
|
||||||
WARN_MSG("Stream already online, cancelling");
|
WARN_MSG("Stream already online, cancelling");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
std::map<std::string, std::string> overrides;
|
std::map<std::string, std::string> overrides;
|
||||||
overrides["throughboot"] = "";
|
overrides["throughboot"] = "";
|
||||||
|
@ -382,11 +396,6 @@ namespace Mist {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!Util::startInput(streamName, "push://INTERNAL_ONLY:"+config->getString("input"), true, true, overrides)) {//manually override stream url to start the buffer
|
if (!Util::startInput(streamName, "push://INTERNAL_ONLY:"+config->getString("input"), true, true, overrides)) {//manually override stream url to start the buffer
|
||||||
if(isSingular()){
|
|
||||||
pullLock.post();
|
|
||||||
pullLock.close();
|
|
||||||
pullLock.unlink();
|
|
||||||
}
|
|
||||||
WARN_MSG("Could not start buffer, cancelling");
|
WARN_MSG("Could not start buffer, cancelling");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -396,10 +405,6 @@ namespace Mist {
|
||||||
|
|
||||||
if (!openStreamSource()){
|
if (!openStreamSource()){
|
||||||
FAIL_MSG("Unable to connect to source");
|
FAIL_MSG("Unable to connect to source");
|
||||||
if(isSingular()){
|
|
||||||
pullLock.post();
|
|
||||||
pullLock.close();
|
|
||||||
}
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -413,11 +418,6 @@ namespace Mist {
|
||||||
if (myMeta.tracks.size() == 0){
|
if (myMeta.tracks.size() == 0){
|
||||||
nProxy.userClient.finish();
|
nProxy.userClient.finish();
|
||||||
finish();
|
finish();
|
||||||
if(isSingular()){
|
|
||||||
pullLock.post();
|
|
||||||
pullLock.close();
|
|
||||||
pullLock.unlink();
|
|
||||||
}
|
|
||||||
INFO_MSG("No tracks found, cancelling");
|
INFO_MSG("No tracks found, cancelling");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -434,11 +434,6 @@ namespace Mist {
|
||||||
|
|
||||||
nProxy.userClient.finish();
|
nProxy.userClient.finish();
|
||||||
finish();
|
finish();
|
||||||
if(isSingular()){
|
|
||||||
pullLock.post();
|
|
||||||
pullLock.close();
|
|
||||||
pullLock.unlink();
|
|
||||||
}
|
|
||||||
INFO_MSG("Stream input %s closing clean; reason: %s", streamName.c_str(), reason.c_str());
|
INFO_MSG("Stream input %s closing clean; reason: %s", streamName.c_str(), reason.c_str());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,7 +20,7 @@ namespace Mist {
|
||||||
public:
|
public:
|
||||||
Input(Util::Config * cfg);
|
Input(Util::Config * cfg);
|
||||||
virtual int run();
|
virtual int run();
|
||||||
virtual void onCrash();
|
virtual void onCrash(){}
|
||||||
virtual int boot(int argc, char * argv[]);
|
virtual int boot(int argc, char * argv[]);
|
||||||
virtual ~Input() {};
|
virtual ~Input() {};
|
||||||
|
|
||||||
|
|
|
@ -463,7 +463,7 @@ namespace Mist {
|
||||||
}
|
}
|
||||||
//Track is set to "New track request", assign new track id and create shared memory page
|
//Track is set to "New track request", assign new track id and create shared memory page
|
||||||
//This indicates that the 'current key' part of the element is set to contain the original track id from the pushing process
|
//This indicates that the 'current key' part of the element is set to contain the original track id from the pushing process
|
||||||
if (value & 0x80000000) {
|
if (config->is_active && (value & 0x80000000)) {
|
||||||
if (value & 0x40000000) {
|
if (value & 0x40000000) {
|
||||||
unsigned long finalMap = value & ~0xC0000000;
|
unsigned long finalMap = value & ~0xC0000000;
|
||||||
//Register the new track as an active track.
|
//Register the new track as an active track.
|
||||||
|
@ -480,9 +480,15 @@ namespace Mist {
|
||||||
|
|
||||||
char tempMetaName[NAME_BUFFER_SIZE];
|
char tempMetaName[NAME_BUFFER_SIZE];
|
||||||
snprintf(tempMetaName, NAME_BUFFER_SIZE, SHM_TRACK_META, config->getString("streamname").c_str(), finalMap);
|
snprintf(tempMetaName, NAME_BUFFER_SIZE, SHM_TRACK_META, config->getString("streamname").c_str(), finalMap);
|
||||||
tMeta.init(tempMetaName, 8388608, false);
|
tMeta.init(tempMetaName, 8388608, false, false);
|
||||||
|
if (!tMeta){continue;}//abort for now if page doesn't exist yet
|
||||||
|
|
||||||
//The page exist, now we try to read in the metadata of the track
|
char firstPage[NAME_BUFFER_SIZE];
|
||||||
|
snprintf(firstPage, NAME_BUFFER_SIZE, SHM_TRACK_INDEX, config->getString("streamname").c_str(), finalMap);
|
||||||
|
nProxy.metaPages[finalMap].init(firstPage, SHM_TRACK_INDEX_SIZE, false, false);
|
||||||
|
if (!nProxy.metaPages[finalMap]){continue;}//abort for now if page doesn't exist yet
|
||||||
|
|
||||||
|
//The pages exist, now we try to read in the metadata of the track
|
||||||
|
|
||||||
//Store the size of the dtsc packet to read.
|
//Store the size of the dtsc packet to read.
|
||||||
unsigned int len = ntohl(((int *)tMeta.mapped)[1]);
|
unsigned int len = ntohl(((int *)tMeta.mapped)[1]);
|
||||||
|
@ -505,11 +511,6 @@ namespace Mist {
|
||||||
userConn.setTrackId(index, finalMap);
|
userConn.setTrackId(index, finalMap);
|
||||||
userConn.setKeynum(index, 0x0000);
|
userConn.setKeynum(index, 0x0000);
|
||||||
|
|
||||||
|
|
||||||
char firstPage[NAME_BUFFER_SIZE];
|
|
||||||
snprintf(firstPage, NAME_BUFFER_SIZE, SHM_TRACK_INDEX, config->getString("streamname").c_str(), finalMap);
|
|
||||||
nProxy.metaPages[finalMap].init(firstPage, SHM_TRACK_INDEX_SIZE, false);
|
|
||||||
|
|
||||||
//Update the metadata for this track
|
//Update the metadata for this track
|
||||||
updateTrackMeta(finalMap);
|
updateTrackMeta(finalMap);
|
||||||
hasPush = true;
|
hasPush = true;
|
||||||
|
@ -536,7 +537,7 @@ namespace Mist {
|
||||||
}
|
}
|
||||||
|
|
||||||
//The track id is set to the value of a track that we are currently negotiating about
|
//The track id is set to the value of a track that we are currently negotiating about
|
||||||
if (negotiatingTracks.count(value)) {
|
if (config->is_active && negotiatingTracks.count(value)) {
|
||||||
//If the metadata page for this track is not yet registered, initialize it
|
//If the metadata page for this track is not yet registered, initialize it
|
||||||
if (!nProxy.metaPages.count(value) || !nProxy.metaPages[value].mapped) {
|
if (!nProxy.metaPages.count(value) || !nProxy.metaPages[value].mapped) {
|
||||||
char tempMetaName[NAME_BUFFER_SIZE];
|
char tempMetaName[NAME_BUFFER_SIZE];
|
||||||
|
@ -740,7 +741,10 @@ namespace Mist {
|
||||||
strName = strName.substr(0, (strName.find_first_of("+ ")));
|
strName = strName.substr(0, (strName.find_first_of("+ ")));
|
||||||
IPC::sharedPage serverCfg(SHM_CONF, DEFAULT_CONF_PAGE_SIZE, false, false); ///< Contains server configuration and capabilities
|
IPC::sharedPage serverCfg(SHM_CONF, DEFAULT_CONF_PAGE_SIZE, false, false); ///< Contains server configuration and capabilities
|
||||||
IPC::semaphore configLock(SEM_CONF, O_CREAT | O_RDWR, ACCESSPERMS, 1);
|
IPC::semaphore configLock(SEM_CONF, O_CREAT | O_RDWR, ACCESSPERMS, 1);
|
||||||
configLock.wait();
|
if (!configLock.tryWaitOneSecond()){
|
||||||
|
INFO_MSG("Aborting stream config refresh: locking took longer than expected");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
DTSC::Scan streamCfg = DTSC::Scan(serverCfg.mapped, serverCfg.len).getMember("streams").getMember(strName);
|
DTSC::Scan streamCfg = DTSC::Scan(serverCfg.mapped, serverCfg.len).getMember("streams").getMember(strName);
|
||||||
long long tmpNum;
|
long long tmpNum;
|
||||||
|
|
||||||
|
@ -783,8 +787,6 @@ namespace Mist {
|
||||||
resumeMode = tmpNum;
|
resumeMode = tmpNum;
|
||||||
}
|
}
|
||||||
|
|
||||||
configLock.post();
|
|
||||||
configLock.close();
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue