include/SDL_thread.h
author David Ludwig <dludwig@pobox.com>
Sat, 29 Nov 2014 10:09:30 -0500
changeset 9247 eddb899239fe
parent 9125 e004bdb812ce
child 9619 b94b6d0bff0f
permissions -rw-r--r--
WinRT: bug and data-integrity fixes for SDL_GetPrefPath()

This change does a few things, all with regards to the WinRT implementation of
SDL_GetPrefPath():

1. it fixes a bug whereby SDL_GetPrefPath() did not create the directory it
returned. On other SDL platforms, SDL_GetPrefPath() will create separate
directories for its 'org' and 'app' folders. Without this, attempts to create
files in the pref-path would fail, unless those directories were first created
by the app, or by some other library the app used. This change makes sure
that these directories get created, before SDL_GetPrefPath() returns to its
caller(s).


2. it defaults to having SDL_GetPrefPath() return a WinRT 'Local' folder
on all platforms. Previously, for Windows Store apps, it would have used a
different, 'Roaming' folder. Files in Roaming folders can be automatically,
and synchronized across multiple devices by Windows. This synchronization can
happen while the app runs, with new files being copied into a running app's
pref-path. Unless an app is specifically designed to handle this scenario,
there is a chance that save-data could be overwritten in unwanted or
unexpected ways.

The default is now to use a Local folder, which does not get synchronized, and
which is arguably a bit safer to use. Apps that wish to use Roaming folders
can do so by setting SDL_HINT_WINRT_PREF_PATH_ROOT to "roaming", however it
is recommended that one first read Microsoft's documentation for Roaming
files, a link to which is provided in README-winrt.md.

To preserve older pref-path selection behavior (found in SDL 2.0.3, as well as
many pre-2.0.4 versions of SDL from hg.libsdl.org), which uses a Roaming path
in Windows Store apps, and a Local path in Windows Phone, set
SDL_HINT_WINRT_PREF_PATH_ROOT to "old".

Please note that Roaming paths are not supported on Windows Phone 8.0, due to
limitations in the OS itself. Attempts to use this will fail.
(Windows Phone 8.1 does not have this limitation, however.)


3. It makes SDL_GetPrefPath(), when on Windows Phone 8.0, and when
SDL_HINT_WINRT_PREF_PATH_ROOT is set to "roaming", return NULL, rather than
silently defaulting to a Local path (then switching to a Roaming path if and
when the user upgraded to Windows Phone 8.1).
slouken@0
     1
/*
slouken@5535
     2
  Simple DirectMedia Layer
slouken@8149
     3
  Copyright (C) 1997-2014 Sam Lantinga <slouken@libsdl.org>
slouken@0
     4
slouken@5535
     5
  This software is provided 'as-is', without any express or implied
slouken@5535
     6
  warranty.  In no event will the authors be held liable for any damages
slouken@5535
     7
  arising from the use of this software.
slouken@0
     8
slouken@5535
     9
  Permission is granted to anyone to use this software for any purpose,
slouken@5535
    10
  including commercial applications, and to alter it and redistribute it
slouken@5535
    11
  freely, subject to the following restrictions:
slouken@0
    12
slouken@5535
    13
  1. The origin of this software must not be misrepresented; you must not
slouken@5535
    14
     claim that you wrote the original software. If you use this software
slouken@5535
    15
     in a product, an acknowledgment in the product documentation would be
slouken@5535
    16
     appreciated but is not required.
slouken@5535
    17
  2. Altered source versions must be plainly marked as such, and must not be
slouken@5535
    18
     misrepresented as being the original software.
slouken@5535
    19
  3. This notice may not be removed or altered from any source distribution.
slouken@0
    20
*/
slouken@0
    21
slouken@0
    22
#ifndef _SDL_thread_h
slouken@0
    23
#define _SDL_thread_h
slouken@0
    24
slouken@1895
    25
/**
slouken@3407
    26
 *  \file SDL_thread.h
slouken@7191
    27
 *
slouken@3407
    28
 *  Header for the SDL thread management routines.
slouken@1895
    29
 */
slouken@0
    30
slouken@1356
    31
#include "SDL_stdinc.h"
slouken@1358
    32
#include "SDL_error.h"
slouken@0
    33
slouken@0
    34
/* Thread synchronization primitives */
slouken@7391
    35
#include "SDL_atomic.h"
slouken@0
    36
#include "SDL_mutex.h"
slouken@0
    37
slouken@0
    38
#include "begin_code.h"
slouken@0
    39
/* Set up for C function definitions, even when using C++ */
slouken@0
    40
#ifdef __cplusplus
slouken@0
    41
extern "C" {
slouken@0
    42
#endif
slouken@0
    43
slouken@0
    44
/* The SDL thread structure, defined in SDL_thread.c */
slouken@0
    45
struct SDL_Thread;
slouken@0
    46
typedef struct SDL_Thread SDL_Thread;
slouken@0
    47
slouken@3578
    48
/* The SDL thread ID */
slouken@3578
    49
typedef unsigned long SDL_threadID;
slouken@3578
    50
slouken@7393
    51
/* Thread local storage ID, 0 is the invalid ID */
icculus@7482
    52
typedef unsigned int SDL_TLSID;
slouken@7391
    53
philipp@7653
    54
/**
philipp@7653
    55
 *  The SDL thread priority.
slouken@5506
    56
 *
philipp@7653
    57
 *  \note On many systems you require special privileges to set high priority.
slouken@5506
    58
 */
slouken@5506
    59
typedef enum {
slouken@5506
    60
    SDL_THREAD_PRIORITY_LOW,
slouken@5506
    61
    SDL_THREAD_PRIORITY_NORMAL,
slouken@5506
    62
    SDL_THREAD_PRIORITY_HIGH
slouken@5506
    63
} SDL_ThreadPriority;
slouken@5506
    64
philipp@7653
    65
/**
philipp@7653
    66
 *  The function passed to SDL_CreateThread().
philipp@7653
    67
 *  It is passed a void* user context parameter and returns an int.
slouken@4866
    68
 */
slouken@4866
    69
typedef int (SDLCALL * SDL_ThreadFunction) (void *data);
slouken@4866
    70
slouken@5086
    71
#if defined(__WIN32__) && !defined(HAVE_LIBC)
slouken@3407
    72
/**
slouken@3407
    73
 *  \file SDL_thread.h
slouken@7191
    74
 *
slouken@3407
    75
 *  We compile SDL into a DLL. This means, that it's the DLL which
slouken@3407
    76
 *  creates a new thread for the calling process with the SDL_CreateThread()
slouken@3407
    77
 *  API. There is a problem with this, that only the RTL of the SDL.DLL will
slouken@7191
    78
 *  be initialized for those threads, and not the RTL of the calling
slouken@3407
    79
 *  application!
slouken@7191
    80
 *
slouken@3407
    81
 *  To solve this, we make a little hack here.
slouken@7191
    82
 *
slouken@3407
    83
 *  We'll always use the caller's _beginthread() and _endthread() APIs to
slouken@3407
    84
 *  start a new thread. This way, if it's the SDL.DLL which uses this API,
slouken@3407
    85
 *  then the RTL of SDL.DLL will be used to create the new thread, and if it's
slouken@3407
    86
 *  the application, then the RTL of the application will be used.
slouken@7191
    87
 *
slouken@3407
    88
 *  So, in short:
slouken@7191
    89
 *  Always use the _beginthread() and _endthread() of the calling runtime
slouken@3407
    90
 *  library!
slouken@3407
    91
 */
slouken@1471
    92
#define SDL_PASSED_BEGINTHREAD_ENDTHREAD
slouken@1895
    93
#include <process.h>            /* This has _beginthread() and _endthread() defined! */
icculus@1190
    94
slouken@1895
    95
typedef uintptr_t(__cdecl * pfnSDL_CurrentBeginThread) (void *, unsigned,
slouken@1895
    96
                                                        unsigned (__stdcall *
slouken@1895
    97
                                                                  func) (void
slouken@1895
    98
                                                                         *),
slouken@1895
    99
                                                        void *arg, unsigned,
slouken@1895
   100
                                                        unsigned *threadID);
slouken@1895
   101
typedef void (__cdecl * pfnSDL_CurrentEndThread) (unsigned code);
icculus@1190
   102
slouken@3407
   103
/**
slouken@3407
   104
 *  Create a thread.
slouken@3407
   105
 */
slouken@2060
   106
extern DECLSPEC SDL_Thread *SDLCALL
icculus@5969
   107
SDL_CreateThread(SDL_ThreadFunction fn, const char *name, void *data,
slouken@2060
   108
                 pfnSDL_CurrentBeginThread pfnBeginThread,
slouken@2060
   109
                 pfnSDL_CurrentEndThread pfnEndThread);
icculus@1190
   110
slouken@3407
   111
/**
slouken@3407
   112
 *  Create a thread.
slouken@3407
   113
 */
icculus@8094
   114
#if defined(SDL_CreateThread) && SDL_DYNAMIC_API
icculus@8094
   115
#undef SDL_CreateThread
icculus@8094
   116
#define SDL_CreateThread(fn, name, data) SDL_CreateThread_REAL(fn, name, data, (pfnSDL_CurrentBeginThread)_beginthreadex, (pfnSDL_CurrentEndThread)_endthreadex)
icculus@8094
   117
#else
slouken@7528
   118
#define SDL_CreateThread(fn, name, data) SDL_CreateThread(fn, name, data, (pfnSDL_CurrentBeginThread)_beginthreadex, (pfnSDL_CurrentEndThread)_endthreadex)
icculus@8094
   119
#endif
slouken@3407
   120
icculus@1190
   121
#else
slouken@3407
   122
slouken@3407
   123
/**
slouken@3407
   124
 *  Create a thread.
icculus@5969
   125
 *
icculus@5969
   126
 *   Thread naming is a little complicated: Most systems have very small
icculus@7981
   127
 *    limits for the string length (Haiku has 32 bytes, Linux currently has 16,
icculus@5969
   128
 *    Visual C++ 6.0 has nine!), and possibly other arbitrary rules. You'll
icculus@5969
   129
 *    have to see what happens with your system's debugger. The name should be
icculus@5969
   130
 *    UTF-8 (but using the naming limits of C identifiers is a better bet).
icculus@5969
   131
 *   There are no requirements for thread naming conventions, so long as the
icculus@5969
   132
 *    string is null-terminated UTF-8, but these guidelines are helpful in
icculus@5969
   133
 *    choosing a name:
icculus@5969
   134
 *
icculus@5969
   135
 *    http://stackoverflow.com/questions/149932/naming-conventions-for-threads
icculus@5969
   136
 *
icculus@5969
   137
 *   If a system imposes requirements, SDL will try to munge the string for
icculus@5969
   138
 *    it (truncate, etc), but the original string contents will be available
icculus@5969
   139
 *    from SDL_GetThreadName().
slouken@3407
   140
 */
slouken@1895
   141
extern DECLSPEC SDL_Thread *SDLCALL
icculus@5969
   142
SDL_CreateThread(SDL_ThreadFunction fn, const char *name, void *data);
slouken@3407
   143
icculus@1190
   144
#endif
slouken@0
   145
slouken@3407
   146
/**
icculus@5969
   147
 * Get the thread name, as it was specified in SDL_CreateThread().
icculus@5969
   148
 *  This function returns a pointer to a UTF-8 string that names the
icculus@5969
   149
 *  specified thread, or NULL if it doesn't have a name. This is internal
icculus@5969
   150
 *  memory, not to be free()'d by the caller, and remains valid until the
icculus@5969
   151
 *  specified thread is cleaned up by SDL_WaitThread().
icculus@5969
   152
 */
icculus@5969
   153
extern DECLSPEC const char *SDLCALL SDL_GetThreadName(SDL_Thread *thread);
icculus@5969
   154
icculus@5969
   155
/**
slouken@3578
   156
 *  Get the thread identifier for the current thread.
slouken@3407
   157
 */
slouken@3578
   158
extern DECLSPEC SDL_threadID SDLCALL SDL_ThreadID(void);
slouken@0
   159
slouken@3407
   160
/**
slouken@3578
   161
 *  Get the thread identifier for the specified thread.
slouken@7191
   162
 *
slouken@3407
   163
 *  Equivalent to SDL_ThreadID() if the specified thread is NULL.
slouken@0
   164
 */
slouken@3578
   165
extern DECLSPEC SDL_threadID SDLCALL SDL_GetThreadID(SDL_Thread * thread);
slouken@0
   166
slouken@3407
   167
/**
slouken@5509
   168
 *  Set the priority for the current thread
slouken@5506
   169
 */
slouken@5509
   170
extern DECLSPEC int SDLCALL SDL_SetThreadPriority(SDL_ThreadPriority priority);
slouken@5506
   171
slouken@5506
   172
/**
icculus@7978
   173
 *  Wait for a thread to finish. Threads that haven't been detached will
icculus@7978
   174
 *  remain (as a "zombie") until this function cleans them up. Not doing so
icculus@7978
   175
 *  is a resource leak.
icculus@7978
   176
 *
icculus@7978
   177
 *  Once a thread has been cleaned up through this function, the SDL_Thread
icculus@7978
   178
 *  that references it becomes invalid and should not be referenced again.
icculus@7978
   179
 *  As such, only one thread may call SDL_WaitThread() on another.
slouken@7191
   180
 *
slouken@3407
   181
 *  The return code for the thread function is placed in the area
slouken@3407
   182
 *  pointed to by \c status, if \c status is not NULL.
icculus@7978
   183
 *
icculus@7978
   184
 *  You may not wait on a thread that has been used in a call to
icculus@7978
   185
 *  SDL_DetachThread(). Use either that function or this one, but not
icculus@7978
   186
 *  both, or behavior is undefined.
icculus@7978
   187
 *
icculus@7978
   188
 *  It is safe to pass NULL to this function; it is a no-op.
slouken@0
   189
 */
slouken@1895
   190
extern DECLSPEC void SDLCALL SDL_WaitThread(SDL_Thread * thread, int *status);
slouken@0
   191
slouken@7391
   192
/**
icculus@7978
   193
 *  A thread may be "detached" to signify that it should not remain until
icculus@7978
   194
 *  another thread has called SDL_WaitThread() on it. Detaching a thread
icculus@7978
   195
 *  is useful for long-running threads that nothing needs to synchronize
icculus@7978
   196
 *  with or further manage. When a detached thread is done, it simply
icculus@7978
   197
 *  goes away.
icculus@7978
   198
 *
icculus@7978
   199
 *  There is no way to recover the return code of a detached thread. If you
icculus@7978
   200
 *  need this, don't detach the thread and instead use SDL_WaitThread().
icculus@7978
   201
 *
icculus@7978
   202
 *  Once a thread is detached, you should usually assume the SDL_Thread isn't
icculus@7978
   203
 *  safe to reference again, as it will become invalid immediately upon
icculus@7978
   204
 *  the detached thread's exit, instead of remaining until someone has called
icculus@7978
   205
 *  SDL_WaitThread() to finally clean it up. As such, don't detach the same
icculus@7978
   206
 *  thread more than once.
icculus@7978
   207
 *
icculus@7978
   208
 *  If a thread has already exited when passed to SDL_DetachThread(), it will
icculus@7978
   209
 *  stop waiting for a call to SDL_WaitThread() and clean up immediately.
icculus@7978
   210
 *  It is not safe to detach a thread that might be used with SDL_WaitThread().
icculus@7978
   211
 *
icculus@7978
   212
 *  You may not call SDL_WaitThread() on a thread that has been detached.
icculus@7978
   213
 *  Use either that function or this one, but not both, or behavior is
icculus@7978
   214
 *  undefined.
icculus@7978
   215
 *
icculus@7978
   216
 *  It is safe to pass NULL to this function; it is a no-op.
icculus@7978
   217
 */
icculus@7978
   218
extern DECLSPEC void SDLCALL SDL_DetachThread(SDL_Thread * thread);
icculus@7978
   219
icculus@7978
   220
/**
slouken@7391
   221
 *  \brief Create an identifier that is globally visible to all threads but refers to data that is thread-specific.
slouken@7391
   222
 *
slouken@7391
   223
 *  \return The newly created thread local storage identifier, or 0 on error
slouken@7391
   224
 *
slouken@7391
   225
 *  \code
slouken@7391
   226
 *  static SDL_SpinLock tls_lock;
slouken@7391
   227
 *  static SDL_TLSID thread_local_storage;
slouken@7391
   228
 * 
slouken@7391
   229
 *  void SetMyThreadData(void *value)
slouken@7391
   230
 *  {
slouken@7391
   231
 *      if (!thread_local_storage) {
slouken@7391
   232
 *          SDL_AtomicLock(&tls_lock);
slouken@7391
   233
 *          if (!thread_local_storage) {
slouken@7391
   234
 *              thread_local_storage = SDL_TLSCreate();
slouken@7391
   235
 *          }
philipp@9125
   236
 *          SDL_AtomicUnlock(&tls_lock);
slouken@7391
   237
 *      }
philipp@9125
   238
 *      SDL_TLSSet(thread_local_storage, value, 0);
slouken@7391
   239
 *  }
slouken@7391
   240
 *  
slouken@7391
   241
 *  void *GetMyThreadData(void)
slouken@7391
   242
 *  {
slouken@7391
   243
 *      return SDL_TLSGet(thread_local_storage);
slouken@7391
   244
 *  }
slouken@7391
   245
 *  \endcode
slouken@7391
   246
 *
slouken@7391
   247
 *  \sa SDL_TLSGet()
slouken@7391
   248
 *  \sa SDL_TLSSet()
slouken@7391
   249
 */
dimitris@7418
   250
extern DECLSPEC SDL_TLSID SDLCALL SDL_TLSCreate(void);
slouken@7391
   251
slouken@7391
   252
/**
slouken@7391
   253
 *  \brief Get the value associated with a thread local storage ID for the current thread.
slouken@7391
   254
 *
slouken@7391
   255
 *  \param id The thread local storage ID
slouken@7391
   256
 *
slouken@7391
   257
 *  \return The value associated with the ID for the current thread, or NULL if no value has been set.
slouken@7391
   258
 *
slouken@7391
   259
 *  \sa SDL_TLSCreate()
slouken@7391
   260
 *  \sa SDL_TLSSet()
slouken@7391
   261
 */
slouken@7391
   262
extern DECLSPEC void * SDLCALL SDL_TLSGet(SDL_TLSID id);
slouken@7391
   263
slouken@7391
   264
/**
slouken@7391
   265
 *  \brief Set the value associated with a thread local storage ID for the current thread.
slouken@7391
   266
 *
slouken@7391
   267
 *  \param id The thread local storage ID
slouken@7391
   268
 *  \param value The value to associate with the ID for the current thread
slouken@7393
   269
 *  \param destructor A function called when the thread exits, to free the value.
slouken@7391
   270
 *
slouken@7391
   271
 *  \return 0 on success, -1 on error
slouken@7391
   272
 *
slouken@7391
   273
 *  \sa SDL_TLSCreate()
slouken@7391
   274
 *  \sa SDL_TLSGet()
slouken@7391
   275
 */
slouken@7393
   276
extern DECLSPEC int SDLCALL SDL_TLSSet(SDL_TLSID id, const void *value, void (*destructor)(void*));
slouken@7391
   277
slouken@0
   278
slouken@0
   279
/* Ends C function definitions when using C++ */
slouken@0
   280
#ifdef __cplusplus
slouken@0
   281
}
slouken@0
   282
#endif
slouken@0
   283
#include "close_code.h"
slouken@0
   284
slouken@0
   285
#endif /* _SDL_thread_h */
slouken@1895
   286
slouken@1895
   287
/* vi: set ts=4 sw=4 expandtab: */