Skip to content

[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

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 31 additions & 0 deletions include/SDL3/SDL_process.h
Original file line number Diff line number Diff line change
Expand Up @@ -425,6 +425,37 @@ extern SDL_DECLSPEC bool SDLCALL SDL_WaitProcess(SDL_Process *process, bool bloc
*/
extern SDL_DECLSPEC void SDLCALL SDL_DestroyProcess(SDL_Process *process);

/**
* Get the current process ID.
*
* It eventually maps to the platform-specific function to get the current process ID (getpid() on Unix and GetCurrentProcessId() on Windows).
* There is no direct usage for it in SDL right now, but you may use this value for debugging or other purposes.
*
* \returns PID of the current process
*
* \threadsafety This function is not thread safe.
*
* \since This function is available since SDL 3.2.0.
*
* \sa SDL_GetCurrentProcessName
*/
extern SDL_DECLSPEC int SDLCALL SDL_GetCurrentProcessId(void);

/**
* Get the current process name.
*
* Returned string is cached by SDL and should not be freed by the caller.
*
* \returns Name of the current process
*
* \threadsafety This function is not thread safe.
*
* \since This function is available since SDL 3.2.0.
*
* \sa SDL_GetCurrentProcessId
*/
extern SDL_DECLSPEC const char *SDLCALL SDL_GetCurrentProcessName(void);

/* Ends C function definitions when using C++ */
#ifdef __cplusplus
}
Expand Down
3 changes: 3 additions & 0 deletions src/SDL.c
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@
#ifdef SDL_PLATFORM_ANDROID
#include "core/android/SDL_android.h"
#endif
#include "process/SDL_process_c.h"

#define SDL_INIT_EVERYTHING ~0U

Expand Down Expand Up @@ -279,6 +280,7 @@ void SDL_InitMainThread(void)
SDL_InitEnvironment();
SDL_InitTicks();
SDL_InitFilesystem();
SDL_InitProcessManagement();

if (!done_info) {
const char *value;
Expand All @@ -301,6 +303,7 @@ static void SDL_QuitMainThread(void)
SDL_QuitTicks();
SDL_QuitEnvironment();
SDL_QuitTLSData();
SDL_QuitProcessManagement();
}

bool SDL_InitSubSystem(SDL_InitFlags flags)
Expand Down
2 changes: 2 additions & 0 deletions src/dynapi/SDL_dynapi.sym
Original file line number Diff line number Diff line change
Expand Up @@ -1248,6 +1248,8 @@ SDL3_0.0.0 {
SDL_GetWindowProgressValue;
SDL_SetRenderTextureAddressMode;
SDL_GetRenderTextureAddressMode;
SDL_GetCurrentProcessId;
SDL_GetCurrentProcessName;
# extra symbols go here (don't modify this line)
local: *;
};
2 changes: 2 additions & 0 deletions src/dynapi/SDL_dynapi_overrides.h
Original file line number Diff line number Diff line change
Expand Up @@ -1273,3 +1273,5 @@
#define SDL_GetWindowProgressValue SDL_GetWindowProgressValue_REAL
#define SDL_SetRenderTextureAddressMode SDL_SetRenderTextureAddressMode_REAL
#define SDL_GetRenderTextureAddressMode SDL_GetRenderTextureAddressMode_REAL
#define SDL_GetCurrentProcessId SDL_GetCurrentProcessId_REAL
#define SDL_GetCurrentProcessName SDL_GetCurrentProcessName_REAL
2 changes: 2 additions & 0 deletions src/dynapi/SDL_dynapi_procs.h
Original file line number Diff line number Diff line change
Expand Up @@ -1281,3 +1281,5 @@ SDL_DYNAPI_PROC(SDL_ProgressState,SDL_GetWindowProgressState,(SDL_Window *a),(a)
SDL_DYNAPI_PROC(float,SDL_GetWindowProgressValue,(SDL_Window *a),(a),return)
SDL_DYNAPI_PROC(bool,SDL_SetRenderTextureAddressMode,(SDL_Renderer *a,SDL_TextureAddressMode b,SDL_TextureAddressMode c),(a,b,c),return)
SDL_DYNAPI_PROC(bool,SDL_GetRenderTextureAddressMode,(SDL_Renderer *a,SDL_TextureAddressMode *b,SDL_TextureAddressMode *c),(a,b,c),return)
SDL_DYNAPI_PROC(int,SDL_GetCurrentProcessId,(void),(),return)
SDL_DYNAPI_PROC(const char*,SDL_GetCurrentProcessName,(void),(),return)
29 changes: 29 additions & 0 deletions src/process/SDL_process.c
Original file line number Diff line number Diff line change
Expand Up @@ -194,3 +194,32 @@ void SDL_DestroyProcess(SDL_Process *process)
SDL_DestroyProperties(process->props);
SDL_free(process);
}

int SDL_GetCurrentProcessId(void)
{
return SDL_SYS_GetCurrentProcessId();
}

static char *CachedCurrentProcessName = NULL;

const char *SDL_GetCurrentProcessName(void)
{
if (!CachedCurrentProcessName) {
CachedCurrentProcessName = SDL_SYS_GetCurrentProcessName();
}

return CachedCurrentProcessName;
}

void SDL_InitProcessManagement(void)
{
}

void SDL_QuitProcessManagement(void)
{
if (CachedCurrentProcessName) {
SDL_free(CachedCurrentProcessName);
}

CachedCurrentProcessName = NULL;
}
28 changes: 28 additions & 0 deletions src/process/SDL_process_c.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2025 Sam Lantinga <[email protected]>

This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.

Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:

1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/

#ifndef SDL_process_c_h_
#define SDL_process_c_h_

extern void SDL_InitProcessManagement(void);
extern void SDL_QuitProcessManagement(void);

#endif
2 changes: 2 additions & 0 deletions src/process/SDL_sysprocess.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,3 +35,5 @@ bool SDL_SYS_CreateProcessWithProperties(SDL_Process *process, SDL_PropertiesID
bool SDL_SYS_KillProcess(SDL_Process *process, bool force);
bool SDL_SYS_WaitProcess(SDL_Process *process, bool block, int *exitcode);
void SDL_SYS_DestroyProcess(SDL_Process *process);
int SDL_SYS_GetCurrentProcessId(void);
char *SDL_SYS_GetCurrentProcessName(void);
10 changes: 10 additions & 0 deletions src/process/dummy/SDL_dummyprocess.c
Original file line number Diff line number Diff line change
Expand Up @@ -45,4 +45,14 @@ void SDL_SYS_DestroyProcess(SDL_Process *process)
return;
}

int SDL_GetCurrentProcessId(void)
{
return -1;
}

char *SDL_SYS_GetCurrentProcessName(void)
{
return NULL;
}

#endif // SDL_PROCESS_DUMMY
18 changes: 18 additions & 0 deletions src/process/posix/SDL_posixprocess.c
Original file line number Diff line number Diff line change
Expand Up @@ -511,4 +511,22 @@ void SDL_SYS_DestroyProcess(SDL_Process *process)
SDL_free(process->internal);
}

int SDL_SYS_GetCurrentProcessId(void)
{
return getpid();
}

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;
}
Comment on lines +519 to +530
Copy link
Contributor

@Kontrabant Kontrabant Mar 29, 2025

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.

Copy link
Contributor

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.

Copy link
Contributor Author

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?

Copy link

@thedarknomad thedarknomad Apr 1, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@MrOnlineCoder

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):

@Kontrabant

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.

Copy link

@thedarknomad thedarknomad Apr 1, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@MrOnlineCoder

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 ;
}

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).

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@MrOnlineCoder

Please check the above advice, also note the issue was auto-closed on libsdl, even though it was not fully implemented.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@MrOnlineCoder

Please check the above advice, also note the issue was auto-closed on libsdl, even though it was not fully implemented.

Copy link
Contributor Author

@MrOnlineCoder MrOnlineCoder Apr 9, 2025

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 ?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nevermind, I didn't read the message carefully, ignore the closing thing I said.


#endif // SDL_PROCESS_POSIX
45 changes: 45 additions & 0 deletions src/process/windows/SDL_windowsprocess.c
Original file line number Diff line number Diff line change
Expand Up @@ -564,4 +564,49 @@ void SDL_SYS_DestroyProcess(SDL_Process *process)
SDL_free(data);
}

int SDL_SYS_GetCurrentProcessId(void)
{
return GetCurrentProcessId();
}

char *SDL_SYS_GetCurrentProcessName(void)
{
DWORD buflen = 128;
WCHAR *path = NULL;
char *result = NULL;
DWORD len = 0;

// Copy paste from SDL_GetBasePath() - should this be a shared function?
while (true) {
void *ptr = SDL_realloc(path, buflen * sizeof(WCHAR));
if (!ptr) {
SDL_free(path);
return NULL;
}

path = (WCHAR *)ptr;

len = GetModuleFileNameW(NULL, path, buflen);
// if it truncated, then len >= buflen - 1
// if there was enough room (or failure), len < buflen - 1
if (len < buflen - 1) {
break;
}

// buffer too small? Try again.
buflen *= 2;
}

if (len == 0) {
SDL_free(path);
WIN_SetError("Couldn't locate our .exe");
return NULL;
}

result = WIN_StringToUTF8W(path);
SDL_free(path);

return result;
}

#endif // SDL_PROCESS_WINDOWS
Loading