-
Notifications
You must be signed in to change notification settings - Fork 2.1k
[WIP] [Process] Add functions to get current process PID and name #12666
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
[WIP] [Process] Add functions to get current process PID and name #12666
Conversation
char *SDL_SYS_GetCurrentProcessName(void) | ||
{ | ||
#if defined(SDL_PLATFORM_MACOS) || defined(SDL_PLATFORM_FREEBSD) | ||
char *processPath = SDL_strdup(getprogname()); | ||
#elif defined(SDL_PLATFORM_LINUX) | ||
char *processPath = SDL_strdup(program_invocation_name); | ||
#else | ||
char *processPath = NULL; | ||
#endif | ||
|
||
return processPath; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This will return the invocation name as found in argv[0], and is incorrect when symlinks are used. Your idea to split the executable path functionality out of the base path functionality is probably the way to go.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That could replace the rather bare-bones SDL_GetExeName() functionality in src/core/unix/SDL_appid.c as well.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please help me clear the confusion on where to actually implement the function for fetching the executable name, or to be exact, what should be the cross-platform approach to it.
We have quite a few platfrom-dependent implenentations for filesystem
module: android, cocoa, haiku, gdk, ps2, psp, unix, windows, vita, etc... While for process
we have only division into windows and unix. Is this because process creation is more standardized than filesystem access? Or does it mean process API may not be supported on some systems like ps2 or haiku?
Some of the SDL_GetBasePath
implementations do not parse the directory name out of executable path, for example Emscripten just uses "/" as a return value, and PS2 returns getcwd()
, which means not every SDL_GetBasePath implementation may contain a valid way to achieve the executable path, that can be used to split into two functions as mentioned above.
How should I proceed?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
but that would possibly mean that instead of just executable filename, we may be interested in full path including the directory and the executable filename, to check both that the filename was not changed, and that the game is run from Steam directory or similar
No, I only meant the actual executable (as stated by the workaround of using args[0], being path-free). In case you do want such checks for the exe source path, we already have SDL_GetBasePath. So a supposed SDL_GetCurrentProcessName() would return myapp (for POSIX) or myapp.exe (for win-like systems).
I also stated the ideal way is to cache it for further access since it won't change, similar to SDL_GetBasePath.
static char *CachedBasePath = NULL;
const char *SDL_GetBasePath(void)
{
if (!CachedBasePath) {
CachedBasePath = SDL_SYS_GetBasePath();
}
return CachedBasePath;
}
there is no single universal way to get the executable name on POSIX platforms
Indeed no. You'd need #ifdefs unfortunately. See SDL_GetExeName() as a starting point.
What I found by looking around (but I don't have a *nix to test them on):
- Haiku: get_next_image_info()
- Linux: /proc/self/exe
This will return the invocation name as found in argv[0], and is incorrect when symlinks are used
Well, technically speaking it is still correct. While not talking about games, at work a very modular production system uses configurable modules for each component and it has only dedicated executables on a *nix system but we have over 40 components starting as processes and each are started as a symlink to the what exe is proper for that component. The way we monitor them is to see the "exe" that started it, which is the symlink. If we had resolved the symlink, we wouldn't know what component we're actually monitoring when it initiates (before configs are loaded and so on). While I know I am talking about enterprise systems here, let's consider SDL can be used for other types of apps as well, not just games :) There are built-in ways to treat this and for those using C++, the filesystem namespace is very easy to use, so I wouldn't worry about it. OTOH, the only reason I proposed argv[0] was as a workaround if the system won't allow a method for that due to sandboxing (I am thinking maybe consoles or some mobile devices possibly?)
That could replace the rather bare-bones SDL_GetExeName() functionality in src/core/unix/SDL_appid.c as well.
Indeed, it's good as a starting point since it covers most
SDL_SYS_GetCurrentProcessName
With the mention that the process name should not contain the path; it's not the same as a pseudo-GetCurrentExeFilePath.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would appreciate assistance in regards to API design and cross-platform code
Not sure it's the best way, but good starting code that I imagine would probably be (this is more or less pseudo code, as I am just typing it here, so typos or compilation errors might occur, but might serve as a starting point; consider some is also guess work :) ):
Process id
include/SDL_process.h
extern SDL_DECLSPEC SDL_ProcessID SDLCALL SDL_GetCurrentProcessID(void); // SDL_ProcessID maybe? depends if the type is different on each platform
src/process/SDL_sysprocess.h
SDL_ProcessID SDL_SYS_GetCurrentProcessID(void); // (or hardcoded type? see above note)
src/process/windows/SDL_windowsprocess.c
SDL_ProcessID SDL_SYS_GetCurrentProcessID(void)
{
return ::GetCurrentProcessId();
}
src/process/posix/SDL_posixprocess.c
SDL_ProcessID SDL_SYS_GetCurrentProcessID(void)
{
return ::getpid();
}
src/process/SDL_process.c
SDL_ProcessID SDL_GetCurrentProcessID(void)
{
return SDL_SYS_GetCurrentProcessID();
}
EXE name
include/SDL_filesystem.h
extern SDL_DECLSPEC char * SDLCALL SDL_GetCurrentExe(void);
// or SDL_GetCurrentExeFilename?
src/filesystem/SDL_sysfilesystem.h
extern char *SDL_SYS_GetCurrentExe(void);
src/filesystem/windows/SDL_sysfilesystem.c
char *SDL_SYS_GetCurrentExe(void)
{
// [GetModuleFileNameW](https://learn.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-getmodulefilenamew)
// remember to switch to char* unicode; check SDL_SYS_GetCurrentDirectory() for an example with WIN_StringToUTF8W
}
src/filesystem/cocoa/SDL_sysfilesystem.m
Bundled app: executablePath
Non-Bundled app: _NSGetExecutablePath
src/filesystem/dummy/SDL_sysfilesystem.c
char *SDL_SYS_GetCurrentExe(void)
{
SDL_Unsupported();
return NULL;
}
src/filesystem/emscripten/SDL_sysfilesystem.c
No clue
src/filesystem/gdk/SDL_sysfilesystem.c
char *SDL_SYS_GetCurrentExe(void)
{
// [GetModuleFileNameA](https://learn.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-getmodulefilenamea)
}
src/filesystem/haiku/SDL_sysfilesystem.c
See this example
src/filesystem/n3ds/SDL_sysfilesystem.c
Most likely no way to get it
src/filesystem/posix/SDL_sysfilesystem.c
char *SDL_SYS_GetCurrentExe(void)
{
// should work with **/proc/self/exe** in most cases; possibly needs handling if the symlink is missing? not sure if this should happen on linux or other posix-es
}
src/filesystem/riscos/SDL_sysfilesystem.c
As far as I could see from the documentation at first glance, there is no way to track the currently running image reliably
src/filesystem/unix/SDL_sysfilesystem.c
char *SDL_SYS_GetCurrentExe(void)
{
// see SDL_GetExeName() or maybe replace it as @Kontrabant suggested
}
src/filesystem/vita/SDL_sysfilesystem.c
Doubtful it can be done on Vita
src/filesystem/SDL_sysfilesystem.c
static char *CachedExeName = NULL;
const char *SDL_GetCurrentExe(void)
{
if (!CachedExeName ) {
CachedExeName = SDL_SYS_GetCurrentExe();
}
return CachedExeName ;
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hey @thedarknomad thanks for such in-depth example, although I was more asking about general idea :D
My concern is that okay for GetCurrentExe to be a part of SDL filesystem api?
Also:
No, I only meant the actual executable (as stated by the workaround of using args[0], being path-free). In case you do want such checks for the exe source path, we already have SDL_GetBasePath. So a supposed SDL_GetCurrentProcessName() would return myapp (for POSIX) or myapp.exe (for win-like systems).
Is it guaranteed on all platforms that "Get the directory where the application was run from." (SDL_GetBasePath wiki) would really equal to the folder where executable is located? There are comments on MacOS and 3DS in the wiki already, but still...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@MrOnlineCoder
Regarding the examples, I am hoping they help you even if a little. They were based on some quick research (as I don't have those platforms) after reading up on the APIs and some articles. Which is also why I can't assure you on their validity.
I don't have those platforms, so I can't test. I am sure there are SOME edge cases, but I wouldn't focus on them as those might be the exception, not the rule. And to be fair, the general programming law is: "I coded this to be used properly as so, I added some protections or workarounds if you call it wrongly like so so that it still works right, but if you bypass those and the app behaves incorrectly, I am not responsible for your stup... pro-activeness" :)
For the exe name function , I recommend you move it to the filesystem category (see my suggestions) and call it SDL_GetExeName (or SDL_GetExecutableName or SDL_GetCurrentExeFilename or whatever else) since it's more of a file-thing than a process thing. Processes have ids or handles, but my topic addressed the process name just to give a general idea.
Also, make sure you remove the pathname to the exe in the pseudo-getexe function. I think if someone does want to see how it was launched (i.e. via some relative path or from the home directory or anything other, they can capture / track main() or WinMain(). As for symlinks, as I said, I don't recommend a resolution on them. Or if you did implement it (I didn't check), make it customizable via a macro. This way if someone wants to track a symlink / shortcut intentionally to diferentiate something versus someone wanting to track a symlink / shortcut to make sure nobody altered the app, they have the full freedom to do so.
I'll check your progress when I get home from work.
P.S. I also got thinking about closed systems and either the dev can use a workaround like SDL Proprties for that, either they hardcode it (it's not like you can change or add a new executable on consoles anyway) so I don't think there is work needed there. If somebody does complain, a simple SDL_SetExeName() would suffice (to keep code portable and not fall back to workarounds like properties).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please check the above advice, also note the issue was auto-closed on libsdl, even though it was not fully implemented.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please check the above advice, also note the issue was auto-closed on libsdl, even though it was not fully implemented.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@thedarknomad hey sorry for late reply, didn't have time to work on that one. What do you mean the issue was auto-closed? The #12615 ?
My attempt to resolve #12615
Adds two functions as requested by issue author:
and
I have to note that this is very rough draft and I would appreciate assistance in regards to API design and cross-platform code, as I am new to this.
Therefore, some key points I would like to mention:
I decided to not go this way because I didn't like the idea of manually/artificially building the SDL_Process structure to represent currently running process - it would require to add all current (and future) properties to SDL_Process object, including stdio streams, add safeguards to all other process functions such as kill/wait/destroy, needing to then introduce a way to check if the provided process is the current one. Moreover, while building the internal
SDL_ProcessData
for SDL_Process member is trivial on POSIX (it requires copying onepid_t
field fromgetpid()
) - on Windows it requires a full PROCESS_INFORMATION structure, needing to provide handles and IDs of process and primary thread - I was not sure what to consider "primary thread" in that case, and if it was okay to assume main thread as such.Therefore I used simpler solution of introducing two new functions. This may be okay unless it's highly desirable to be able to represent current process as fully valid
SDL_Process
instance, as this would mean any possible new features that will useSDL_Process
may be used on the current process too.but that would possibly mean that instead of just executable filename, we may be interested in full path including the directory and the executable filename, to check both that the filename was not changed, and that the game is run from Steam directory or similar. In current PR version I have assumed the more straightforward option - executable filename only, so if program is run as
/home/test/myapp
,SDL_GetCurrentProcessName
should returnmyapp
SDL_GetBasePath
) and my findings online, there is no single universal way to get the executable name on POSIX platforms - it differs for Linux and MacOS at least. Therefore it uses BSD-specific getprogname() and GNU-specific program_invocation_name to return the executable name. I don't know how to handle other platforms or if it's needed at all.SDL_InitProcessManagement
andSDL_QuitProcessManagement
init and quit callbacks to free the cached process name. I am not sure if caching PID is needed, unlessgetpid()
system call cost is worth that.Again, I would appreciate any comments and suggestions in right direction.