diff --git a/neo/CMakeLists.txt b/neo/CMakeLists.txt index ec8fdd15..fe76c9be 100644 --- a/neo/CMakeLists.txt +++ b/neo/CMakeLists.txt @@ -827,7 +827,7 @@ set(WIN32_RESOURCES file(GLOB POSIX_INCLUDES sys/posix/*.h) -file(GLOB POSIX_SOURCES sys/posix/*.cpp sys/posix/*.mm) +file(GLOB POSIX_SOURCES sys/posix/*.cpp) file(GLOB COMMON_INCLUDES sys/common/*.h) file(GLOB COMMON_SOURCES sys/common/*.cpp) @@ -1346,7 +1346,7 @@ else() if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin") list(REMOVE_ITEM POSIX_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/sys/posix/platform_linux.cpp) else() - list(REMOVE_ITEM POSIX_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/sys/posix/platform_osx.mm) + list(REMOVE_ITEM POSIX_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/sys/posix/platform_osx.cpp) endif() list(APPEND RBDOOM3_SOURCES diff --git a/neo/sys/posix/platform_linux.cpp b/neo/sys/posix/platform_linux.cpp index 9cd947dd..8342a00e 100644 --- a/neo/sys/posix/platform_linux.cpp +++ b/neo/sys/posix/platform_linux.cpp @@ -49,17 +49,6 @@ static int cmdargc = 0; #include #endif -/* - ============== - Sys_DefaultSavePath - ============== - */ -const char* Sys_DefaultSavePath() -{ - sprintf( savepath, "%s/.rbdoom3bfg", getenv( "HOME" ) ); - - return savepath.c_str(); -} /* ============== Sys_EXEPath diff --git a/neo/sys/posix/platform_osx.cpp b/neo/sys/posix/platform_osx.cpp new file mode 100644 index 00000000..dd484003 --- /dev/null +++ b/neo/sys/posix/platform_osx.cpp @@ -0,0 +1,493 @@ +/* +=========================================================================== + +Doom 3 GPL Source Code +Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company. +Copyright (C) 2012 Robert Beckebans + +This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?). + +Doom 3 Source Code 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 3 of the License, or +(at your option) any later version. + +Doom 3 Source Code 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 Doom 3 Source Code. If not, see . + +In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below. + +If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA. + +=========================================================================== +*/ +//#include "../../idlib/precompiled.h" +#include "../posix/posix_public.h" +//#include "../sys_local.h" + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +// DG: needed for Sys_ReLaunch() +#include + +static const char** cmdargv = NULL; +static int cmdargc = 0; +// DG end + +/* +============== +Sys_EXEPath +============== +*/ +const char* Sys_EXEPath() +{ + static char path[1024]; + uint32_t size = sizeof( path ); + + if( _NSGetExecutablePath( path, &size ) != 0 ) + { + Sys_Printf( "buffer too small to store exe path, need size %u\n", size ); + path[0] = '\0'; + } + return path; +} + +/* +=============== +Sys_GetProcessorId +=============== +*/ +cpuid_t Sys_GetProcessorId() +{ + return CPUID_GENERIC; +} + +/* +=============== +Sys_GetProcessorString +=============== +*/ +const char* Sys_GetProcessorString() +{ + return "generic"; +} + +/* +=============== +Sys_ClockTicksPerSecond +=============== +*/ +double Sys_ClockTicksPerSecond() +{ + static bool init = false; + static double ret; + size_t len = sizeof( ret ); + int status; + + if( init ) + { + return ret; + } + + status = sysctlbyname( "hw.cpufrequency", &ret, &len, NULL, 0 ); + + if( status == -1 ) + { + common->Printf( "couldn't read systclbyname\n" ); + ret = MeasureClockTicks(); + init = true; + common->Printf( "measured CPU frequency: %g MHz\n", ret / 1000000.0 ); + return ret; + } + + common->Printf( "CPU frequency: %g MHz\n", ret / 1000000.0 ); + init = true; + + return ret; +} + +/* +======================== +Sys_CPUCount + +numLogicalCPUCores - the number of logical CPU per core +numPhysicalCPUCores - the total number of cores per package +numCPUPackages - the total number of packages (physical processors) +======================== +*/ +// RB begin +void Sys_CPUCount( int& numLogicalCPUCores, int& numPhysicalCPUCores, int& numCPUPackages ) +{ + static bool init = false; + + static int s_numLogicalCPUCores; + static int s_numPhysicalCPUCores; + static int s_numCPUPackages; + + size_t len = sizeof( s_numPhysicalCPUCores ); + + if( init ) + { + numPhysicalCPUCores = s_numPhysicalCPUCores; + numLogicalCPUCores = s_numLogicalCPUCores; + numCPUPackages = s_numCPUPackages; + } + + s_numPhysicalCPUCores = 1; + s_numLogicalCPUCores = 1; + s_numCPUPackages = 1; + + + sysctlbyname( "hw.physicalcpu", &s_numPhysicalCPUCores, &len, NULL, 0 ); + sysctlbyname( "hw.logicalcpu", &s_numLogicalCPUCores, &len, NULL, 0 ); + + common->Printf( "CPU processors: %d\n", s_numPhysicalCPUCores ); + common->Printf( "CPU logical cores: %d\n", s_numLogicalCPUCores ); + + numPhysicalCPUCores = s_numPhysicalCPUCores; + numLogicalCPUCores = s_numLogicalCPUCores; + numCPUPackages = s_numCPUPackages; +} +// RB end + +/* +================ +Sys_GetSystemRam +returns in megabytes +================ +*/ +int Sys_GetSystemRam() +{ + int mb, mib[2]; + + mib[0] = CTL_HW; + mib[1] = HW_MEMSIZE; + int64_t size = 0; + size_t len = sizeof( size ); + if( sysctl( mib, 2, &size, &len, NULL, 0 ) == 0 ) + { + mb = size / ( 1024 * 1024 ); + mb = ( mb + 8 ) & ~15; + return mb; + } + + common->Printf( "GetSystemRam: sysctl HW_MEMSIZE failed\n" ); + return 512; +} + + +/* +================== +Sys_DoStartProcess +if we don't fork, this function never returns +the no-fork lets you keep the terminal when you're about to spawn an installer + +if the command contains spaces, system() is used. Otherwise the more straightforward execl ( system() blows though ) +================== +*/ +void Sys_DoStartProcess( const char* exeName, bool dofork ) +{ + bool use_system = false; + if( strchr( exeName, ' ' ) ) + { + use_system = true; + } + else + { + // set exec rights when it's about a single file to execute + struct stat buf; + if( stat( exeName, &buf ) == -1 ) + { + printf( "stat %s failed: %s\n", exeName, strerror( errno ) ); + } + else + { + if( chmod( exeName, buf.st_mode | S_IXUSR ) == -1 ) + { + printf( "cmod +x %s failed: %s\n", exeName, strerror( errno ) ); + } + } + } + if( dofork ) + { + switch( fork() ) + { + case -1: + // main thread + break; + case 0: + if( use_system ) + { + printf( "system %s\n", exeName ); + system( exeName ); + _exit( 0 ); + } + else + { + printf( "execl %s\n", exeName ); + execl( exeName, exeName, NULL ); + printf( "execl failed: %s\n", strerror( errno ) ); + _exit( -1 ); + } + break; + } + } + else + { + if( use_system ) + { + printf( "system %s\n", exeName ); + system( exeName ); + sleep( 1 ); // on some systems I've seen that starting the new process and exiting this one should not be too close + } + else + { + printf( "execl %s\n", exeName ); + execl( exeName, exeName, NULL ); + printf( "execl failed: %s\n", strerror( errno ) ); + } + // terminate + _exit( 0 ); + } +} + +/* + ================== + Sys_DoPreferences + ================== + */ +void Sys_DoPreferences() { } + +#if 0 +/* +================ +Sys_FPU_SetDAZ +================ +*/ +void Sys_FPU_SetDAZ( bool enable ) +{ + /* + DWORD dwData; + + _asm { + movzx ecx, byte ptr enable + and ecx, 1 + shl ecx, 6 + STMXCSR dword ptr dwData + mov eax, dwData + and eax, ~(1<<6) // clear DAX bit + or eax, ecx // set the DAZ bit + mov dwData, eax + LDMXCSR dword ptr dwData + } + */ +} + +/* +================ +Sys_FPU_SetFTZ +================ +*/ +void Sys_FPU_SetFTZ( bool enable ) +{ + /* + DWORD dwData; + + _asm { + movzx ecx, byte ptr enable + and ecx, 1 + shl ecx, 15 + STMXCSR dword ptr dwData + mov eax, dwData + and eax, ~(1<<15) // clear FTZ bit + or eax, ecx // set the FTZ bit + mov dwData, eax + LDMXCSR dword ptr dwData + } + */ +} +#endif + +/* +======================== +Sys_GetCmdLine +======================== +*/ +const char* Sys_GetCmdLine() +{ + // DG: don't use this, use cmdargv and cmdargc instead! + return "TODO Sys_GetCmdLine"; +} + +/* +======================== +Sys_ReLaunch +======================== +*/ +void Sys_ReLaunch() +{ + // DG: implementing this... basic old fork() exec() (+ setsid()) routine.. + // NOTE: this function used to have parameters: the commandline arguments, but as one string.. + // for Linux/Unix we want one char* per argument so we'll just add the friggin' + // " +set com_skipIntroVideos 1" to the other commandline arguments in this function. + + int ret = fork(); + if( ret < 0 ) + idLib::Error( "Sys_ReLaunch(): Couldn't fork(), reason: %s ", strerror( errno ) ); + + if( ret == 0 ) + { + // child process + + // get our own session so we don't depend on the (soon to be killed) + // parent process anymore - else we'll freeze + pid_t sId = setsid(); + if( sId == ( pid_t ) - 1 ) + { + idLib::Error( "Sys_ReLaunch(): setsid() failed! Reason: %s ", strerror( errno ) ); + } + + // close all FDs (except for stdin/out/err) so we don't leak FDs + DIR* devfd = opendir( "/dev/fd" ); + if( devfd != NULL ) + { + struct dirent entry; + struct dirent* result; + while( readdir_r( devfd, &entry, &result ) == 0 ) + { + const char* filename = result->d_name; + char* endptr = NULL; + long int fd = strtol( filename, &endptr, 0 ); + if( endptr != filename && fd > STDERR_FILENO ) + close( fd ); + } + } + else + { + idLib::Warning( "Sys_ReLaunch(): Couldn't open /dev/fd/ - will leak file descriptors. Reason: %s", strerror( errno ) ); + } + + // + 3 because "+set" "com_skipIntroVideos" "1" - and note that while we'll skip + // one (the first) cmdargv argument, we need one more pointer for NULL at the end. + int argc = cmdargc + 3; + const char** argv = ( const char** )calloc( argc, sizeof( char* ) ); + + int i; + for( i = 0; i < cmdargc - 1; ++i ) + argv[i] = cmdargv[i + 1]; // ignore cmdargv[0] == executable name + + // add +set com_skipIntroVideos 1 + argv[i++] = "+set"; + argv[i++] = "com_skipIntroVideos"; + argv[i++] = "1"; + // execv expects NULL terminated array + argv[i] = NULL; + + const char* exepath = Sys_EXEPath(); + + errno = 0; + execv( exepath, ( char** )argv ); + // we only get here if execv() fails, else the executable is restarted + idLib::Error( "Sys_ReLaunch(): WTF exec() failed! Reason: %s ", strerror( errno ) ); + + } + else + { + // original process + // just do a clean shutdown + cmdSystem->AppendCommandText( "quit\n" ); + } + // DG end +} + +// OS X doesn't have clock_gettime() +int clock_gettime( clk_id_t clock, struct timespec* tp ) +{ + switch( clock ) + { + case CLOCK_MONOTONIC_RAW: + case CLOCK_MONOTONIC: + { + clock_serv_t clock_ref; + mach_timespec_t tm; + host_name_port_t self = mach_host_self(); + memset( &tm, 0, sizeof( tm ) ); + if( KERN_SUCCESS != host_get_clock_service( self, SYSTEM_CLOCK, &clock_ref ) ) + { + mach_port_deallocate( mach_task_self(), self ); + return -1; + } + if( KERN_SUCCESS != clock_get_time( clock_ref, &tm ) ) + { + mach_port_deallocate( mach_task_self(), self ); + return -1; + } + mach_port_deallocate( mach_task_self(), self ); + mach_port_deallocate( mach_task_self(), clock_ref ); + tp->tv_sec = tm.tv_sec; + tp->tv_nsec = tm.tv_nsec; + break; + } + + case CLOCK_REALTIME: + default: + { + struct timeval now; + if( KERN_SUCCESS != gettimeofday( &now, NULL ) ) + { + return -1; + } + tp->tv_sec = now.tv_sec; + tp->tv_nsec = now.tv_usec * 1000; + break; + } + } + return 0; +} + +/* +=============== +main +=============== +*/ +int main( int argc, const char** argv ) +{ + // DG: needed for Sys_ReLaunch() + cmdargc = argc; + cmdargv = argv; + // DG end + + Posix_EarlyInit( ); + + if( argc > 1 ) + { + common->Init( argc - 1, &argv[1], NULL ); + } + else + { + common->Init( 0, NULL, NULL ); + } + + Posix_LateInit( ); + + while( 1 ) + { + common->Frame(); + } +} diff --git a/neo/sys/posix/posix_main.cpp b/neo/sys/posix/posix_main.cpp index 21269096..3ccb9c2c 100644 --- a/neo/sys/posix/posix_main.cpp +++ b/neo/sys/posix/posix_main.cpp @@ -85,6 +85,22 @@ idCVar com_pid( "com_pid", "0", CVAR_INTEGER | CVAR_INIT | CVAR_SYSTEM, "process static int set_exit = 0; static char exit_spawn[ 1024 ]; +/* + ============== + Sys_DefaultSavePath + ============== + */ +const char* Sys_DefaultSavePath() +{ +#ifdef __APPLE__ + sprintf( savepath, "%s/Library/Application Support/rbdoom3bfg", getenv( "HOME" ) ); +#else + sprintf( savepath, "%s/.rbdoom3bfg", getenv( "HOME" ) ); +#endif + + return savepath.c_str(); +} + /* ================ Posix_Exit