mirror of
https://github.com/melonDS-emu/melonDS.git
synced 2024-11-14 05:17:40 -07:00
Merge b7e933a32e
into 5e8beb3ab7
This commit is contained in:
commit
aa6ca7ebc0
@ -83,7 +83,7 @@ void Compiler::Comp_JumpTo(u32 addr, bool forceNonConstantCycles)
|
||||
// doesn't matter if we put garbage in the MSbs there
|
||||
if (addr & 0x2)
|
||||
{
|
||||
cpu9->CodeRead32(addr-2, true) >> 16;
|
||||
cpu9->CodeRead32(addr-2, true);
|
||||
cycles += cpu9->CodeCycles;
|
||||
cpu9->CodeRead32(addr+2, false);
|
||||
cycles += CurCPU->CodeCycles;
|
||||
@ -437,4 +437,4 @@ void Compiler::T_Comp_BL_Merged()
|
||||
Comp_JumpTo(target);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -717,7 +717,7 @@ ARMJIT_Memory::ARMJIT_Memory(melonDS::NDS& nds) : NDS(nds)
|
||||
}
|
||||
#else
|
||||
char fastmemPidName[snprintf(NULL, 0, "/melondsfastmem%d", getpid()) + 1];
|
||||
sprintf(fastmemPidName, "/melondsfastmem%d", getpid());
|
||||
snprintf(fastmemPidName, sizeof(fastmemPidName), "/melondsfastmem%d", getpid());
|
||||
MemoryFile = shm_open(fastmemPidName, O_RDWR | O_CREAT | O_EXCL, 0600);
|
||||
if (MemoryFile == -1)
|
||||
{
|
||||
@ -1432,4 +1432,4 @@ void* ARMJIT_Memory::GetFuncForAddr(ARM* cpu, u32 addr, bool store, int size) co
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -209,8 +209,6 @@ if (WIN32)
|
||||
endif()
|
||||
|
||||
if (APPLE)
|
||||
target_sources(melonDS PRIVATE sem_timedwait.cpp)
|
||||
|
||||
# Copy icon into the bundle
|
||||
set(RESOURCE_FILES "${CMAKE_SOURCE_DIR}/res/melon.icns")
|
||||
target_sources(melonDS PUBLIC "${RESOURCE_FILES}")
|
||||
|
@ -59,6 +59,8 @@ void CameraFrameDumper::present(const QVideoFrame& _frame)
|
||||
case QVideoFrameFormat::Format_NV12:
|
||||
cam->feedFrame_NV12((u8*)frame.bits(0), (u8*)frame.bits(1), frame.width(), frame.height());
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
frame.unmap();
|
||||
|
@ -58,7 +58,7 @@ protected:
|
||||
void timerEvent(QTimerEvent* event) override;
|
||||
|
||||
private slots:
|
||||
void done(int r);
|
||||
void done(int r) override;
|
||||
|
||||
void on_chkChangeTime_clicked(bool checked);
|
||||
void on_chkResetTime_clicked(bool checked);
|
||||
|
@ -1077,13 +1077,13 @@ std::optional<DSi_NAND::NANDImage> EmuInstance::loadNAND(const std::array<u8, DS
|
||||
auto firmcfg = localCfg.GetTable("Firmware");
|
||||
|
||||
// we store relevant strings as UTF-8, so we need to convert them to UTF-16
|
||||
auto converter = wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t>{};
|
||||
//auto converter = wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t>{};
|
||||
|
||||
// setting up username
|
||||
std::u16string username = converter.from_bytes(firmcfg.GetString("Username"));
|
||||
size_t usernameLength = std::min(username.length(), (size_t) 10);
|
||||
auto username = firmcfg.GetQString("Username");
|
||||
size_t usernameLength = std::min(username.length(), (qsizetype) 10);
|
||||
memset(&settings.Nickname, 0, sizeof(settings.Nickname));
|
||||
memcpy(&settings.Nickname, username.data(), usernameLength * sizeof(char16_t));
|
||||
memcpy(&settings.Nickname, username.utf16(), usernameLength * sizeof(char16_t));
|
||||
|
||||
// setting language
|
||||
settings.Language = static_cast<Firmware::Language>(firmcfg.GetInt("Language"));
|
||||
@ -1096,10 +1096,10 @@ std::optional<DSi_NAND::NANDImage> EmuInstance::loadNAND(const std::array<u8, DS
|
||||
settings.BirthdayDay = firmcfg.GetInt("BirthdayDay");
|
||||
|
||||
// setup message
|
||||
std::u16string message = converter.from_bytes(firmcfg.GetString("Message"));
|
||||
size_t messageLength = std::min(message.length(), (size_t) 26);
|
||||
auto message = firmcfg.GetQString("Message");
|
||||
size_t messageLength = std::min(message.length(), (qsizetype) 26);
|
||||
memset(&settings.Message, 0, sizeof(settings.Message));
|
||||
memcpy(&settings.Message, message.data(), messageLength * sizeof(char16_t));
|
||||
memcpy(&settings.Message, message.utf16(), messageLength * sizeof(char16_t));
|
||||
|
||||
// TODO: make other items configurable?
|
||||
}
|
||||
@ -1660,14 +1660,12 @@ void EmuInstance::customizeFirmware(Firmware& firmware, bool overridesettings) n
|
||||
auto firmcfg = localCfg.GetTable("Firmware");
|
||||
|
||||
// setting up username
|
||||
std::string orig_username = firmcfg.GetString("Username");
|
||||
if (!orig_username.empty())
|
||||
auto username = firmcfg.GetQString("Username");
|
||||
if (!username.isEmpty())
|
||||
{ // If the frontend defines a username, take it. If not, leave the existing one.
|
||||
std::u16string username = std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t>{}.from_bytes(
|
||||
orig_username);
|
||||
size_t usernameLength = std::min(username.length(), (size_t) 10);
|
||||
size_t usernameLength = std::min(username.length(), (qsizetype) 10);
|
||||
currentData.NameLength = usernameLength;
|
||||
memcpy(currentData.Nickname, username.data(), usernameLength * sizeof(char16_t));
|
||||
memcpy(currentData.Nickname, username.utf16(), usernameLength * sizeof(char16_t));
|
||||
}
|
||||
|
||||
auto language = static_cast<Firmware::Language>(firmcfg.GetInt("Language"));
|
||||
@ -1697,12 +1695,10 @@ void EmuInstance::customizeFirmware(Firmware& firmware, bool overridesettings) n
|
||||
}
|
||||
|
||||
// setup message
|
||||
std::string orig_message = firmcfg.GetString("Message");
|
||||
if (!orig_message.empty())
|
||||
auto message = firmcfg.GetQString("Message");
|
||||
if (!message.isEmpty())
|
||||
{
|
||||
std::u16string message = std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t>{}.from_bytes(
|
||||
orig_message);
|
||||
size_t messageLength = std::min(message.length(), (size_t) 26);
|
||||
size_t messageLength = std::min(message.length(), (qsizetype) 26);
|
||||
currentData.MessageLength = messageLength;
|
||||
memcpy(currentData.Message, message.data(), messageLength * sizeof(char16_t));
|
||||
}
|
||||
|
@ -428,9 +428,9 @@ void EmuThread::run()
|
||||
double actualfps = (59.8261 * 263.0) / nlines;
|
||||
int inst = emuInstance->instanceID;
|
||||
if (inst == 0)
|
||||
sprintf(melontitle, "[%d/%.0f] melonDS " MELONDS_VERSION, fps, actualfps);
|
||||
snprintf(melontitle, sizeof(melontitle), "[%d/%.0f] melonDS " MELONDS_VERSION, fps, actualfps);
|
||||
else
|
||||
sprintf(melontitle, "[%d/%.0f] melonDS (%d)", fps, fpstarget, inst+1);
|
||||
snprintf(melontitle, sizeof(melontitle), "[%d/%.0f] melonDS (%d)", fps, fpstarget, inst+1);
|
||||
changeWindowTitle(melontitle);
|
||||
}
|
||||
}
|
||||
@ -445,9 +445,9 @@ void EmuThread::run()
|
||||
|
||||
int inst = emuInstance->instanceID;
|
||||
if (inst == 0)
|
||||
sprintf(melontitle, "melonDS " MELONDS_VERSION);
|
||||
snprintf(melontitle, sizeof(melontitle), "melonDS " MELONDS_VERSION);
|
||||
else
|
||||
sprintf(melontitle, "melonDS (%d)", inst+1);
|
||||
snprintf(melontitle, sizeof(melontitle), "melonDS (%d)", inst+1);
|
||||
changeWindowTitle(melontitle);
|
||||
|
||||
SDL_Delay(75);
|
||||
|
@ -403,6 +403,8 @@ void LANDialog::doUpdatePlayerList()
|
||||
case LAN::Player_Disconnected:
|
||||
status = "Connection lost";
|
||||
break;
|
||||
case LAN::Player_None:
|
||||
break;
|
||||
}
|
||||
model->item(i, 2)->setText(status);
|
||||
|
||||
|
@ -48,7 +48,7 @@ public:
|
||||
}
|
||||
|
||||
private slots:
|
||||
void done(int r);
|
||||
void done(int r) override;
|
||||
|
||||
private:
|
||||
Ui::LANStartHostDialog* ui;
|
||||
@ -76,7 +76,7 @@ private slots:
|
||||
void onGameSelectionChanged(const QItemSelection& cur, const QItemSelection& prev);
|
||||
void on_tvAvailableGames_doubleClicked(QModelIndex index);
|
||||
void onDirectConnect();
|
||||
void done(int r);
|
||||
void done(int r) override;
|
||||
|
||||
void doUpdateDiscoveryList();
|
||||
|
||||
@ -105,7 +105,7 @@ protected:
|
||||
|
||||
private slots:
|
||||
void on_btnLeaveGame_clicked();
|
||||
void done(int r);
|
||||
void done(int r) override;
|
||||
|
||||
void doUpdatePlayerList();
|
||||
|
||||
|
@ -54,7 +54,7 @@ public:
|
||||
}
|
||||
|
||||
private slots:
|
||||
void done(int r);
|
||||
void done(int r) override;
|
||||
|
||||
//
|
||||
|
||||
|
@ -187,7 +187,7 @@ void NetplayDialog::doUpdatePlayerList(Netplay::Player* players, int num)
|
||||
|
||||
char ip[32];
|
||||
u32 addr = player->Address;
|
||||
sprintf(ip, "%d.%d.%d.%d", addr&0xFF, (addr>>8)&0xFF, (addr>>16)&0xFF, addr>>24);
|
||||
snprintf(ip, sizeof(ip), "%d.%d.%d.%d", addr&0xFF, (addr>>8)&0xFF, (addr>>16)&0xFF, addr>>24);
|
||||
model->setItem(i, 4, new QStandardItem(ip));
|
||||
}
|
||||
}
|
||||
|
@ -876,7 +876,7 @@ bool ScreenPanelGL::createContext()
|
||||
if (ourwin->getWindowID() != 0)
|
||||
{
|
||||
if (windowinfo.has_value())
|
||||
if (glContext = parentwin->getOGLContext()->CreateSharedContext(*windowinfo))
|
||||
if ((glContext = parentwin->getOGLContext()->CreateSharedContext(*windowinfo)))
|
||||
glContext->DoneCurrent();
|
||||
}
|
||||
else
|
||||
@ -885,7 +885,7 @@ bool ScreenPanelGL::createContext()
|
||||
GL::Context::Version{GL::Context::Profile::Core, 4, 3},
|
||||
GL::Context::Version{GL::Context::Profile::Core, 3, 2}};
|
||||
if (windowinfo.has_value())
|
||||
if (glContext = GL::Context::Create(*windowinfo, versionsToTry))
|
||||
if ((glContext = GL::Context::Create(*windowinfo, versionsToTry)))
|
||||
glContext->DoneCurrent();
|
||||
}
|
||||
|
||||
|
@ -125,7 +125,7 @@ void TitleManagerDialog::createTitleItem(u32 category, u32 titleid)
|
||||
*(u32*)&gamecode[0] = *(u32*)&header.GameCode[0];
|
||||
gamecode[4] = '\0';
|
||||
char extra[128];
|
||||
sprintf(extra, "\n(title ID: %s · %08x/%08x · version %08x)", gamecode, category, titleid, version);
|
||||
snprintf(extra, sizeof(extra), "\n(title ID: %s · %08x/%08x · version %08x)", gamecode, category, titleid, version);
|
||||
|
||||
QListWidgetItem* item = new QListWidgetItem(title + QString(extra));
|
||||
item->setIcon(icon);
|
||||
@ -481,7 +481,7 @@ void TitleImportDialog::accept()
|
||||
network = new QNetworkAccessManager(this);
|
||||
|
||||
char url[256];
|
||||
sprintf(url, "http://nus.cdn.t.shop.nintendowifi.net/ccs/download/%08x%08x/tmd", titleid[1], titleid[0]);
|
||||
snprintf(url, sizeof(url), "http://nus.cdn.t.shop.nintendowifi.net/ccs/download/%08x%08x/tmd", titleid[1], titleid[0]);
|
||||
|
||||
QNetworkRequest req;
|
||||
req.setUrl(QUrl(url));
|
||||
|
@ -152,14 +152,14 @@ void WifiSettingsDialog::on_cbxDirectAdapter_currentIndexChanged(int sel)
|
||||
melonDS::AdapterData* adapter = &adapters[sel];
|
||||
char tmp[64];
|
||||
|
||||
sprintf(tmp, "%02X:%02X:%02X:%02X:%02X:%02X",
|
||||
adapter->MAC[0], adapter->MAC[1], adapter->MAC[2],
|
||||
adapter->MAC[3], adapter->MAC[4], adapter->MAC[5]);
|
||||
snprintf(tmp, sizeof(tmp), "%02X:%02X:%02X:%02X:%02X:%02X",
|
||||
adapter->MAC[0], adapter->MAC[1], adapter->MAC[2],
|
||||
adapter->MAC[3], adapter->MAC[4], adapter->MAC[5]);
|
||||
ui->lblAdapterMAC->setText(QString(tmp));
|
||||
|
||||
sprintf(tmp, "%d.%d.%d.%d",
|
||||
adapter->IP_v4[0], adapter->IP_v4[1],
|
||||
adapter->IP_v4[2], adapter->IP_v4[3]);
|
||||
snprintf(tmp, sizeof(tmp), "%d.%d.%d.%d",
|
||||
adapter->IP_v4[0], adapter->IP_v4[1],
|
||||
adapter->IP_v4[2], adapter->IP_v4[3]);
|
||||
ui->lblAdapterIP->setText(QString(tmp));
|
||||
}
|
||||
|
||||
|
@ -1,488 +0,0 @@
|
||||
/*
|
||||
* s e m _ t i m e d w a i t
|
||||
*
|
||||
* Function:
|
||||
* Implements a version of sem_timedwait().
|
||||
*
|
||||
* Description:
|
||||
* Not all systems implement sem_timedwait(), which is a version of
|
||||
* sem_wait() with a timeout. Mac OS X is one example, at least up to
|
||||
* and including version 10.6 (Leopard). If such a function is needed,
|
||||
* this code provides a reasonable implementation, which I think is
|
||||
* compatible with the standard version, although possibly less
|
||||
* efficient. It works by creating a thread that interrupts a normal
|
||||
* sem_wait() call after the specified timeout.
|
||||
*
|
||||
* Call:
|
||||
*
|
||||
* The Linux man pages say:
|
||||
*
|
||||
* #include <semaphore.h>
|
||||
*
|
||||
* int sem_timedwait(sem_t *sem, const struct timespec *abs_timeout);
|
||||
*
|
||||
* sem_timedwait() is the same as sem_wait(), except that abs_timeout
|
||||
* specifies a limit on the amount of time that the call should block if
|
||||
* the decrement cannot be immediately performed. The abs_timeout argument
|
||||
* points to a structure that specifies an absolute timeout in seconds and
|
||||
* nanoseconds since the Epoch (00:00:00, 1 January 1970). This structure
|
||||
* is defined as follows:
|
||||
*
|
||||
* struct timespec {
|
||||
* time_t tv_sec; Seconds
|
||||
* long tv_nsec; Nanoseconds [0 .. 999999999]
|
||||
* };
|
||||
*
|
||||
* If the timeout has already expired by the time of the call, and the
|
||||
* semaphore could not be locked immediately, then sem_timedwait() fails
|
||||
* with a timeout error (errno set to ETIMEDOUT).
|
||||
* If the operation can be performed immediately, then sem_timedwait()
|
||||
* never fails with a timeout error, regardless of the value of abs_timeout.
|
||||
* Furthermore, the validity of abs_timeout is not checked in this case.
|
||||
*
|
||||
* Limitations:
|
||||
*
|
||||
* The mechanism used involves sending a SIGUSR2 signal to the thread
|
||||
* calling sem_timedwait(). The handler for this signal is set to a null
|
||||
* routine which does nothing, and with any flags for the signal
|
||||
* (eg SA_RESTART) cleared. Note that this effective disabling of the
|
||||
* SIGUSR2 signal is a side-effect of using this routine, and means it
|
||||
* may not be a completely transparent plug-in replacement for a
|
||||
* 'normal' sig_timedwait() call. Since OS X does not declare the
|
||||
* sem_timedwait() call in its standard include files, the relevant
|
||||
* declaration (shown above in the man pages extract) will probably have
|
||||
* to be added to any code that uses this.
|
||||
*
|
||||
* Compiling:
|
||||
* This compiles and runs cleanly on OS X (10.6) with gcc with the
|
||||
* -Wall -ansi -pedantic flags. On Linux, using -ansi causes a sweep of
|
||||
* compiler complaints about the timespec structure, but it compiles
|
||||
* and works fine with just -Wall -pedantic. (Since Linux provides
|
||||
* sem_timedwait() anyway, this really isn't needed on Linux.) However,
|
||||
* since Linux provides sem_timedwait anyway, the sem_timedwait()
|
||||
* code in this file is only compiled on OS X, and is a null on other
|
||||
* systems.
|
||||
*
|
||||
* Testing:
|
||||
* This file contains a test program that exercises the sem_timedwait
|
||||
* code. It is compiled if the pre-processor variable TEST is defined.
|
||||
* For more details, see the comments for the test routine at the end
|
||||
* of the file.
|
||||
*
|
||||
* Author: Keith Shortridge, AAO.
|
||||
*
|
||||
* History:
|
||||
* 8th Sep 2009. Original version. KS.
|
||||
* 24th Sep 2009. Added test that the calling thread still exists before
|
||||
* trying to set the timed-out flag. KS.
|
||||
* 2nd Oct 2009. No longer restores the original SIGUSR2 signal handler.
|
||||
* See comments in the body of the code for more details.
|
||||
* Prototypes for now discontinued internal routines removed.
|
||||
* 12th Aug 2010. Added the cleanup handler, so that this code no longer
|
||||
* leaks resources if the calling thread is cancelled. KS.
|
||||
* 21st Sep 2011. Added copyright notice below. Modified header comments
|
||||
* to describe the use of SIGUSR2 more accurately in the
|
||||
* light of the 2/10/09 change above. Now undefs DEBUG
|
||||
* before defining it, to avoid any possible clash. KS.
|
||||
* 14th Feb 2012. Tidied out a number of TABs that had got into the
|
||||
* code. KS.
|
||||
* 6th May 2013. Copyright notice modified to one based on the MIT licence,
|
||||
* which is more permissive than the previous notice. KS.
|
||||
*
|
||||
* Copyright (c) Australian Astronomical Observatory (AAO), (2013).
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifdef __APPLE__
|
||||
|
||||
#include <semaphore.h>
|
||||
#include <time.h>
|
||||
#include <sys/time.h>
|
||||
#include <pthread.h>
|
||||
#include <errno.h>
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/fcntl.h>
|
||||
#include <setjmp.h>
|
||||
|
||||
#include "sem_timedwait.h"
|
||||
|
||||
/* Some useful definitions - TRUE, FALSE, and DEBUG */
|
||||
|
||||
#undef TRUE
|
||||
#define TRUE 1
|
||||
#undef FALSE
|
||||
#define FALSE 0
|
||||
#undef DEBUG
|
||||
#define DEBUG printf
|
||||
|
||||
/* A structure of type timeoutDetails is passed to the thread used to
|
||||
* implement the timeout.
|
||||
*/
|
||||
|
||||
typedef struct {
|
||||
struct timespec delay; /* Specifies the delay, relative to now */
|
||||
pthread_t callingThread; /* The thread doing the sem_wait call */
|
||||
volatile short *timedOutShort; /* Address of a flag set to indicate that
|
||||
* the timeout was triggered. */
|
||||
} timeoutDetails;
|
||||
|
||||
/* A structure of type cleanupDetails is passed to the thread cleanup
|
||||
* routine which is called at the end of the routine or if the thread calling
|
||||
* it is cancelled.
|
||||
*/
|
||||
|
||||
typedef struct {
|
||||
pthread_t *threadIdAddr; /* Address of the variable that holds
|
||||
* the Id of the timeout thread. */
|
||||
struct sigaction *sigHandlerAddr; /* Address of the old signal action
|
||||
* handler. */
|
||||
volatile short *timedOutShort; /* Address of a flag set to indicate that
|
||||
* the timeout was triggered. */
|
||||
} cleanupDetails;
|
||||
|
||||
/* Forward declarations of internal routines */
|
||||
|
||||
static void* timeoutThreadMain (void* passedPtr);
|
||||
static int triggerSignal (int Signal, pthread_t Thread);
|
||||
static void ignoreSignal (int Signal);
|
||||
static void timeoutThreadCleanup (void* passedPtr);
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/*
|
||||
* s e m _ t i m e d w a i t
|
||||
*
|
||||
* This is the main code for the sem_timedwait() implementation.
|
||||
*/
|
||||
|
||||
int sem_timedwait (
|
||||
sem_t *sem,
|
||||
const struct timespec *abs_timeout)
|
||||
{
|
||||
int result = 0; /* Code returned by this routine 0 or -1 */
|
||||
|
||||
/* "Under no circumstances shall the function fail if the semaphore
|
||||
* can be locked immediately". So we try to get it quickly to see if we
|
||||
* can avoid all the timeout overheads.
|
||||
*/
|
||||
|
||||
if (sem_trywait(sem) == 0) {
|
||||
|
||||
/* Yes, got it immediately. */
|
||||
|
||||
result = 0;
|
||||
|
||||
} else {
|
||||
|
||||
/* No, we've got to do it with a sem_wait() call and a thread to run
|
||||
* the timeout. First, work out the time from now to the specified
|
||||
* timeout, which we will pass to the timeout thread in a way that can
|
||||
* be used to pass to nanosleep(). So we need this in seconds and
|
||||
* nanoseconds. Along the way, we check for an invalid passed time,
|
||||
* and for one that's already expired.
|
||||
*/
|
||||
|
||||
if ((abs_timeout->tv_nsec < 0) || (abs_timeout->tv_nsec > 1000000000)) {
|
||||
|
||||
/* Passed time is invalid */
|
||||
|
||||
result = -1;
|
||||
errno = EINVAL;
|
||||
|
||||
} else {
|
||||
|
||||
struct timeval currentTime; /* Time now */
|
||||
long secsToWait,nsecsToWait; /* Seconds and nsec to delay */
|
||||
gettimeofday (¤tTime,NULL);
|
||||
secsToWait = abs_timeout->tv_sec - currentTime.tv_sec;
|
||||
nsecsToWait = (abs_timeout->tv_nsec - (currentTime.tv_usec * 1000));
|
||||
while (nsecsToWait < 0) {
|
||||
nsecsToWait += 1000000000;
|
||||
secsToWait--;
|
||||
}
|
||||
if ((secsToWait < 0) || ((secsToWait == 0) && (nsecsToWait < 0))) {
|
||||
|
||||
/* Time has passed. Report an immediate timeout. */
|
||||
|
||||
result = -1;
|
||||
errno = ETIMEDOUT;
|
||||
|
||||
} else {
|
||||
|
||||
/* We're going to have to do a sem_wait() with a timeout thread.
|
||||
* The thread will wait the specified time, then will issue a
|
||||
* SIGUSR2 signal that will interrupt the sem_wait() call.
|
||||
* We pass the thread the id of the current thread, the delay,
|
||||
* and the address of a flag to set on a timeout, so we can
|
||||
* distinguish an interrupt caused by the timeout thread from
|
||||
* one caused by some other signal.
|
||||
*/
|
||||
|
||||
volatile short timedOut; /* Flag to set on timeout */
|
||||
timeoutDetails details; /* All the stuff the thread must know */
|
||||
struct sigaction oldSignalAction; /* Current signal setting */
|
||||
pthread_t timeoutThread; /* Id of timeout thread */
|
||||
cleanupDetails cleaningDetails; /* What the cleanup routine needs */
|
||||
int oldCancelState; /* Previous cancellation state */
|
||||
int ignoreCancelState; /* Used in call, but ignored */
|
||||
int createStatus; /* Status of pthread_create() call */
|
||||
|
||||
/* If the current thread is cancelled (and CML does do this)
|
||||
* we don't want to leave our timer thread running - if we've
|
||||
* started the thread we want to make sure we join it in order
|
||||
* to release its resources. So we set a cleanup handler to
|
||||
* do this. We pass it the address of the structure that will
|
||||
* hold all it needs to know. While we set all this up,
|
||||
* we prevent ourselves being cancelled, so all this data is
|
||||
* coherent.
|
||||
*/
|
||||
|
||||
pthread_setcancelstate (PTHREAD_CANCEL_DISABLE,&oldCancelState);
|
||||
timeoutThread = (pthread_t) 0;
|
||||
cleaningDetails.timedOutShort = &timedOut;
|
||||
cleaningDetails.threadIdAddr = &timeoutThread;
|
||||
cleaningDetails.sigHandlerAddr = &oldSignalAction;
|
||||
pthread_cleanup_push (timeoutThreadCleanup,&cleaningDetails);
|
||||
|
||||
/* Set up the details for the thread. Clear the timeout flag,
|
||||
* record the current SIGUSR2 action settings so we can restore
|
||||
* them later.
|
||||
*/
|
||||
|
||||
details.delay.tv_sec = secsToWait;
|
||||
details.delay.tv_nsec = nsecsToWait;
|
||||
details.callingThread = pthread_self();
|
||||
details.timedOutShort = &timedOut;
|
||||
timedOut = FALSE;
|
||||
sigaction (SIGUSR2,NULL,&oldSignalAction);
|
||||
|
||||
/* Start up the timeout thread. Once we've done that, we can
|
||||
* restore the previous cancellation state.
|
||||
*/
|
||||
|
||||
createStatus = pthread_create(&timeoutThread,NULL,
|
||||
timeoutThreadMain, (void*)&details);
|
||||
pthread_setcancelstate (oldCancelState,&ignoreCancelState);
|
||||
|
||||
if (createStatus < 0) {
|
||||
|
||||
/* Failed to create thread. errno will already be set properly */
|
||||
|
||||
result = -1;
|
||||
|
||||
} else {
|
||||
|
||||
/* Thread created OK. This is where we wait for the semaphore.
|
||||
*/
|
||||
|
||||
if (sem_wait(sem) == 0) {
|
||||
|
||||
/* Got the semaphore OK. We return zero, and all's well. */
|
||||
|
||||
result = 0;
|
||||
|
||||
} else {
|
||||
|
||||
/* If we got a -1 error from sem_wait(), it may be because
|
||||
* it was interrupted by a timeout, or failed for some
|
||||
* other reason. We check for the expected timeout
|
||||
* condition, which is an 'interrupted' status and the
|
||||
* timeout flag set by the timeout thread. We report that as
|
||||
* a timeout error. Anything else is some other error and
|
||||
* errno is already set properly.
|
||||
*/
|
||||
|
||||
result = -1;
|
||||
if (errno == EINTR) {
|
||||
if (timedOut) errno = ETIMEDOUT;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* The cleanup routine - timeoutThreadCleanup() - packages up
|
||||
* any tidying up that is needed, including joining with the
|
||||
* timer thread. This will be called if the current thread is
|
||||
* cancelled, but we need it to happen anyway, so we set the
|
||||
* execute flag true here as we remove it from the list of
|
||||
* cleanup routines to be called. So normally, this line amounts
|
||||
* to calling timeoutThreadCleanup().
|
||||
*/
|
||||
|
||||
pthread_cleanup_pop (TRUE);
|
||||
}
|
||||
}
|
||||
}
|
||||
return (result);
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/*
|
||||
* t i m e o u t T h r e a d C l e a n u p
|
||||
*
|
||||
* This internal routine tidies up at the end of a sem_timedwait() call.
|
||||
* It is set as a cleanup routine for the current thread (not the timer
|
||||
* thread) so it is executed even if the thread is cancelled. This is
|
||||
* important, as we need to tidy up the timeout thread. If we took the
|
||||
* semaphore (in other words, if we didn't timeout) then the timer thread
|
||||
* will still be running, sitting in its nanosleep() call, and we need
|
||||
* to cancel it. If the timer thread did signal a timeout then it will
|
||||
* now be closing down. In either case, we need to join it (using a call
|
||||
* to pthread_join()) or its resources will never be released.
|
||||
* The single argument is a pointer to a cleanupDetails structure that has
|
||||
* all the routine needs to know.
|
||||
*/
|
||||
|
||||
static void timeoutThreadCleanup (void* passedPtr)
|
||||
{
|
||||
/* Get what we need from the structure we've been passed. */
|
||||
|
||||
cleanupDetails *detailsPtr = (cleanupDetails*) passedPtr;
|
||||
short timedOut = *(detailsPtr->timedOutShort);
|
||||
pthread_t timeoutThread = *(detailsPtr->threadIdAddr);
|
||||
|
||||
/* If we created the thread, stop it - doesn't matter if it's no longer
|
||||
* running, pthread_cancel can handle that. We make sure we wait for it
|
||||
* to complete, because it is this pthread_join() call that releases any
|
||||
* memory the thread may have allocated. Note that cancelling a thread is
|
||||
* generally not a good idea, because of the difficulty of cleaning up
|
||||
* after it, but this is a very simple thread that does nothing but call
|
||||
* nanosleep(), and that we can cancel quite happily.
|
||||
*/
|
||||
|
||||
if (!timedOut) pthread_cancel(timeoutThread);
|
||||
pthread_join(timeoutThread,NULL);
|
||||
|
||||
/* The code originally restored the old action handler, which generally
|
||||
* was the default handler that caused the task to exit. Just occasionally,
|
||||
* there seem to be cases where the signal is still queued and ready to
|
||||
* trigger even though the thread that presumably sent it off just before
|
||||
* it was cancelled has finished. I had thought that once we'd joined
|
||||
* that thread, we could be sure of not seeing the signal, but that seems
|
||||
* not to be the case, and so restoring a handler that will allow the task
|
||||
* to crash is not a good idea, and so the line below has been commented
|
||||
* out.
|
||||
*
|
||||
* sigaction (SIGUSR2,detailsPtr->sigHandlerAddr,NULL);
|
||||
*/
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/*
|
||||
* t i m e o u t T h r e a d M a i n
|
||||
*
|
||||
* This internal routine is the main code for the timeout thread.
|
||||
* The single argument is a pointer to a timeoutDetails structure that has
|
||||
* all the thread needs to know - thread to signal, delay time, and the
|
||||
* address of a flag to set if it triggers a timeout.
|
||||
*/
|
||||
|
||||
static void* timeoutThreadMain (void* passedPtr)
|
||||
{
|
||||
void* Return = (void*) 0;
|
||||
|
||||
/* We grab all the data held in the calling thread right now. In some
|
||||
* cases, we find that the calling thread has vanished and released
|
||||
* its memory, including the details structure, by the time the timeout
|
||||
* expires, and then we get an access violation when we try to set the
|
||||
* 'timed out' flag.
|
||||
*/
|
||||
|
||||
timeoutDetails details = *((timeoutDetails*) passedPtr);
|
||||
struct timespec requestedDelay = details.delay;
|
||||
|
||||
/* We do a nanosleep() for the specified delay, and then trigger a
|
||||
* timeout. Note that we allow for the case where the nanosleep() is
|
||||
* interrupted, and restart it for the remaining time. If the
|
||||
* thread that is doing the sem_wait() call gets the semaphore, it
|
||||
* will cancel this thread, which is fine as we aren't doing anything
|
||||
* other than a sleep and a signal.
|
||||
*/
|
||||
|
||||
for (;;) {
|
||||
struct timespec remainingDelay;
|
||||
if (nanosleep (&requestedDelay,&remainingDelay) == 0) {
|
||||
break;
|
||||
} else if (errno == EINTR) {
|
||||
requestedDelay = remainingDelay;
|
||||
} else {
|
||||
Return = (void*) errno;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* We've completed the delay without being cancelled, so we now trigger
|
||||
* the timeout by sending a signal to the calling thread. And that's it,
|
||||
* although we set the timeout flag first to indicate that it was us
|
||||
* that interrupted the sem_wait() call. One precaution: before we
|
||||
* try to set the timed-out flag, make sure the calling thread still
|
||||
* exists - this may not be the case if things are closing down a bit
|
||||
* messily. We check this quickly using a zero test signal.
|
||||
*/
|
||||
|
||||
if (pthread_kill(details.callingThread,0) == 0) {
|
||||
*(details.timedOutShort) = TRUE;
|
||||
if (triggerSignal (SIGUSR2,details.callingThread) < 0) {
|
||||
Return = (void*) errno;
|
||||
}
|
||||
}
|
||||
|
||||
return Return;
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/*
|
||||
* t r i g g e r S i g n a l
|
||||
*
|
||||
* This is a general purpose routine that sends a specified signal to
|
||||
* a specified thread, setting up a signal handler that does nothing,
|
||||
* and then giving the signal. The only effect will be to interrupt any
|
||||
* operation that is currently blocking - in this case, we expect this to
|
||||
* be a sem_wait() call.
|
||||
*/
|
||||
|
||||
static int triggerSignal (int Signal, pthread_t Thread)
|
||||
{
|
||||
int Result = 0;
|
||||
struct sigaction SignalDetails;
|
||||
SignalDetails.sa_handler = ignoreSignal;
|
||||
SignalDetails.sa_flags = 0;
|
||||
(void) sigemptyset(&SignalDetails.sa_mask);
|
||||
if ((Result = sigaction(Signal,&SignalDetails,NULL)) == 0) {
|
||||
Result = pthread_kill(Thread,Signal);
|
||||
}
|
||||
return Result;
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/*
|
||||
* i g n o r e S i g n a l
|
||||
*
|
||||
* And this is the signal handler that does nothing. (It clears its argument,
|
||||
* but this has no effect and prevents a compiler warning about an unused
|
||||
* argument.)
|
||||
*/
|
||||
|
||||
static void ignoreSignal (int Signal) {
|
||||
Signal = 0;
|
||||
}
|
||||
|
||||
#endif
|
@ -1,8 +0,0 @@
|
||||
#ifndef __SEM_TIMEDWAIT_H
|
||||
#define __SEM_TIMEDWAIT_H
|
||||
|
||||
#ifdef __APPLE__
|
||||
int sem_timedwait(sem_t *sem, const struct timespec *abs_timeout);
|
||||
#endif
|
||||
|
||||
#endif
|
@ -653,6 +653,8 @@ void LAN::ProcessHostEvent(ENetEvent& event)
|
||||
enet_packet_destroy(event.packet);
|
||||
}
|
||||
break;
|
||||
case ENET_EVENT_TYPE_NONE:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@ -777,6 +779,8 @@ void LAN::ProcessClientEvent(ENetEvent& event)
|
||||
enet_packet_destroy(event.packet);
|
||||
}
|
||||
break;
|
||||
case ENET_EVENT_TYPE_NONE:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -54,7 +54,9 @@ const u8 kServerMAC[6] = {0x00, 0xAB, 0x33, 0x28, 0x99, 0x44};
|
||||
// https://stackoverflow.com/questions/5404277/porting-clock-gettime-to-windows
|
||||
|
||||
struct timespec { long tv_sec; long tv_nsec; };
|
||||
#define CLOCK_MONOTONIC 1312
|
||||
#ifndef CLOCK_MONOTONIC
|
||||
#define CLOCK_MONOTONIC 1
|
||||
#endif
|
||||
|
||||
int clock_gettime(int, struct timespec *spec)
|
||||
{
|
||||
|
@ -726,6 +726,8 @@ void ProcessHost()
|
||||
}
|
||||
}
|
||||
break;
|
||||
case ENET_EVENT_TYPE_NONE:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -822,6 +824,8 @@ printf("birf\n");
|
||||
}
|
||||
}
|
||||
break;
|
||||
case ENET_EVENT_TYPE_NONE:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user