source: trunk/libtransmission/platform.c @ 5164

Last change on this file since 5164 was 5164, checked in by charles, 13 years ago

better win32 thread support

  • Property svn:keywords set to Date Rev Author Id
File size: 10.2 KB
Line 
1/******************************************************************************
2 * $Id: platform.c 5164 2008-02-28 16:40:31Z charles $
3 *
4 * Copyright (c) 2005-2008 Transmission authors and contributors
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation
9 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 * and/or sell copies of the Software, and to permit persons to whom the
11 * Software is furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 * DEALINGS IN THE SOFTWARE.
23 *****************************************************************************/
24
25#ifdef __BEOS__
26  #include <signal.h> 
27  #include <fs_info.h>
28  #include <FindDirectory.h>
29  #include <kernel/OS.h>
30  #define BEOS_MAX_THREADS 256
31#elif defined(WIN32)
32  #include <windows.h>
33  #include <shlobj.h> /* for CSIDL_APPDATA, CSIDL_PROFILE */
34#else
35  #define _XOPEN_SOURCE 500 /* needed for recursive locks. */
36  #ifndef __USE_UNIX98
37  #define __USE_UNIX98 /* some older Linuxes need it spelt out for them */
38  #endif
39  #include <pthread.h>
40#endif
41
42#include <assert.h>
43#include <stdio.h>
44#include <stdlib.h>
45#include <string.h>
46
47#include <sys/types.h>
48#include <dirent.h>
49#include <fcntl.h>
50#include <unistd.h> /* getuid getpid close */
51
52#include "transmission.h"
53#include "platform.h"
54#include "trcompat.h"
55#include "utils.h"
56
57/***
58****  THREADS
59***/
60
61#ifdef __BEOS__
62typedef thread_id tr_thread_id;
63#elif defined(WIN32)
64typedef DWORD tr_thread_id;
65#else
66typedef pthread_t tr_thread_id;
67#endif
68
69static tr_thread_id
70tr_getCurrentThread( void )
71{
72#ifdef __BEOS__
73    return find_thread( NULL );
74#elif defined(WIN32)
75    return GetCurrentThreadId();
76#else
77    return pthread_self( );
78#endif
79}
80
81static int
82tr_areThreadsEqual( tr_thread_id a, tr_thread_id b )
83{
84#ifdef __BEOS__
85    return a == b;
86#elif defined(WIN32)
87    return a == b;
88#else
89    return pthread_equal( a, b );
90#endif
91}
92
93struct tr_thread
94{
95    void          (* func ) ( void * );
96    void           * arg;
97    const char     * name;
98    tr_thread_id     thread;
99#ifdef WIN32
100    HANDLE           thread_handle;
101#endif
102};
103
104int
105tr_amInThread ( const tr_thread * t )
106{
107    return tr_areThreadsEqual( tr_getCurrentThread(), t->thread );
108}
109
110#ifdef WIN32
111#define ThreadFuncReturnType unsigned WINAPI
112#else
113#define ThreadFuncReturnType void
114#endif
115
116static ThreadFuncReturnType
117ThreadFunc( void * _t )
118{
119    tr_thread * t = _t;
120    const char * name = t->name;
121
122#ifdef __BEOS__
123    /* This is required because on BeOS, SIGINT is sent to each thread,
124       which kills them not nicely */
125    signal( SIGINT, SIG_IGN );
126#endif
127
128    tr_dbg( "Thread '%s' started", name );
129    t->func( t->arg );
130    tr_dbg( "Thread '%s' exited", name );
131
132#ifdef WIN32
133    _endthreadex( 0 );
134    return 0;
135#endif
136}
137
138tr_thread *
139tr_threadNew( void (*func)(void *),
140              void * arg,
141              const char * name )
142{
143    tr_thread * t = tr_new0( tr_thread, 1 );
144
145#ifdef __BEOS__
146    t->thread = spawn_thread( (void*)ThreadFunc, name, B_NORMAL_PRIORITY, t );
147    resume_thread( t->thread );
148#elif defined(WIN32)
149    unsigned id;
150    t->thread_handle = (HANDLE) _beginthreadex( NULL, 0, &ThreadFunc, t, 0, &id );
151    t->thread = (DWORD) id;
152#else
153    pthread_create( &t->thread, NULL, (void * (*) (void *)) ThreadFunc, t );
154#endif
155    t->func = func;
156    t->arg  = arg;
157    t->name = name;
158
159    return t;
160}
161   
162void
163tr_threadJoin( tr_thread * t )
164{
165    if( t != NULL )
166    {
167#ifdef __BEOS__
168        long exit;
169        wait_for_thread( t->thread, &exit );
170#elif defined(WIN32)
171        WaitForSingleObject( t->thread_handle, INFINITE );
172        CloseHandle( t->thread_handle );
173#else
174        pthread_join( t->thread, NULL );
175#endif
176
177        tr_dbg( "Thread '%s' joined", t->name );
178        t->name = NULL;
179        t->func = NULL;
180        tr_free( t );
181    }
182}
183
184/***
185****  LOCKS
186***/
187
188struct tr_lock
189{
190    int depth;
191#ifdef __BEOS__
192    sem_id lock;
193    thread_id lockThread;
194#elif defined(WIN32)
195    CRITICAL_SECTION lock;
196    DWORD lockThread;
197#else
198    pthread_mutex_t lock;
199    pthread_t lockThread;
200#endif
201};
202
203tr_lock*
204tr_lockNew( void )
205{
206    tr_lock * l = tr_new0( tr_lock, 1 );
207
208#ifdef __BEOS__
209    l->lock = create_sem( 1, "" );
210#elif defined(WIN32)
211    InitializeCriticalSection( &l->lock ); /* critical sections support recursion */
212#else
213    pthread_mutexattr_t attr;
214    pthread_mutexattr_init( &attr );
215    pthread_mutexattr_settype( &attr, PTHREAD_MUTEX_RECURSIVE );
216    pthread_mutex_init( &l->lock, &attr );
217#endif
218
219    return l;
220}
221
222void
223tr_lockFree( tr_lock * l )
224{
225#ifdef __BEOS__
226    delete_sem( l->lock );
227#elif defined(WIN32)
228    DeleteCriticalSection( &l->lock );
229#else
230    pthread_mutex_destroy( &l->lock );
231#endif
232    tr_free( l );
233}
234
235void
236tr_lockLock( tr_lock * l )
237{
238#ifdef __BEOS__
239    acquire_sem( l->lock );
240#elif defined(WIN32)
241    EnterCriticalSection( &l->lock );
242#else
243    pthread_mutex_lock( &l->lock );
244#endif
245    assert( l->depth >= 0 );
246    if( l->depth )
247        assert( tr_areThreadsEqual( l->lockThread, tr_getCurrentThread() ) );
248    l->lockThread = tr_getCurrentThread( );
249    ++l->depth;
250}
251
252int
253tr_lockHave( const tr_lock * l )
254{
255    return ( l->depth > 0 )
256        && ( tr_areThreadsEqual( l->lockThread, tr_getCurrentThread() ) );
257}
258
259void
260tr_lockUnlock( tr_lock * l )
261{
262    assert( l->depth > 0 );
263    assert( tr_areThreadsEqual( l->lockThread, tr_getCurrentThread() ));
264
265    --l->depth;
266    assert( l->depth >= 0 );
267#ifdef __BEOS__
268    release_sem( l->lock );
269#elif defined(WIN32)
270    LeaveCriticalSection( &l->lock );
271#else
272    pthread_mutex_unlock( &l->lock );
273#endif
274}
275
276/***
277****  PATHS
278***/
279
280#if !defined(WIN32) && !defined(__BEOS__) && !defined(__AMIGAOS4__)
281#include <pwd.h>
282#endif
283
284static const char *
285tr_getHomeDirectory( void )
286{
287    static char buf[MAX_PATH_LENGTH];
288    static int init = 0;
289    const char * envHome;
290
291    if( init )
292        return buf;
293
294    envHome = getenv( "HOME" );
295    if( envHome )
296        snprintf( buf, sizeof(buf), "%s", envHome );
297    else {
298#ifdef WIN32
299        SHGetFolderPath( NULL, CSIDL_PROFILE, NULL, 0, buf );
300#elif defined(__BEOS__) || defined(__AMIGAOS4__)
301        *buf = '\0';
302#else
303        struct passwd * pw = getpwuid( getuid() );
304        endpwent();
305        if( pw != NULL )
306            snprintf( buf, sizeof(buf), "%s", pw->pw_dir );
307#endif
308    }
309
310    init = 1;
311    return buf;
312}
313
314
315static void
316tr_migrateResume( const char *oldDirectory, const char *newDirectory )
317{
318    DIR * dirh = opendir( oldDirectory );
319
320    if( dirh != NULL )
321    {
322        struct dirent * dirp;
323
324        while( ( dirp = readdir( dirh ) ) )
325        {
326            if( !strncmp( "resume.", dirp->d_name, 7 ) )
327            {
328                char o[MAX_PATH_LENGTH];
329                char n[MAX_PATH_LENGTH];
330                tr_buildPath( o, sizeof(o), oldDirectory, dirp->d_name, NULL );
331                tr_buildPath( n, sizeof(n), newDirectory, dirp->d_name, NULL );
332                rename( o, n );
333            }
334        }
335
336        closedir( dirh );
337    }
338}
339
340const char *
341tr_getPrefsDirectory( void )
342{
343    static char   buf[MAX_PATH_LENGTH];
344    static int    init = 0;
345    const char * trhome;
346
347    if( init )
348        return buf;
349
350    trhome = getenv( "TRANSMISSION_HOME" );
351    if( trhome != NULL )
352    {
353        strlcpy( buf, trhome, sizeof( buf ) );
354    }
355    else
356    {
357#ifdef __BEOS__
358        find_directory( B_USER_SETTINGS_DIRECTORY,
359                        dev_for_path("/boot"), true,
360                        buf, sizeof( buf ) );
361        strcat( buf, "/Transmission" );
362#elif defined( SYS_DARWIN )
363        tr_buildPath ( buf, sizeof( buf ),
364                       tr_getHomeDirectory( ),
365                       "Library",
366                       "Application Support",
367                       "Transmission",
368                       NULL );
369#elif defined(__AMIGAOS4__)
370        strlcpy( buf, "PROGDIR:.transmission", sizeof( buf ) );
371#elif defined(WIN32)
372        char appdata[MAX_PATH_LENGTH];
373        SHGetFolderPath( NULL, CSIDL_APPDATA, NULL, 0, appdata );
374        tr_buildPath( buf, sizeof(buf),
375                      appdata,
376                      "Transmission",
377                      NULL );
378#else
379        tr_buildPath ( buf, sizeof(buf), tr_getHomeDirectory( ), ".transmission", NULL );
380#endif
381    }
382
383    tr_mkdirp( buf, 0777 );
384    init = 1;
385
386#ifdef SYS_DARWIN
387    char old[MAX_PATH_LENGTH];
388    tr_buildPath ( old, sizeof(old),
389                   tr_getHomeDirectory(), ".transmission", NULL );
390    tr_migrateResume( old, buf );
391    rmdir( old );
392#endif
393
394    return buf;
395}
396
397const char *
398tr_getCacheDirectory( void )
399{
400    static char buf[MAX_PATH_LENGTH];
401    static int  init = 0;
402    static const size_t buflen = sizeof(buf);
403    const char * p;
404
405    if( init )
406        return buf;
407
408    p = tr_getPrefsDirectory();
409#if defined(__BEOS__) || defined(WIN32)
410    tr_buildPath( buf, buflen, p, "Cache", NULL );
411#elif defined( SYS_DARWIN )
412    tr_buildPath( buf, buflen, tr_getHomeDirectory(),
413                  "Library", "Caches", "Transmission", NULL );
414#else
415    tr_buildPath( buf, buflen, p, "cache", NULL );
416#endif
417
418    tr_mkdirp( buf, 0777 );
419    init = 1;
420
421    if( strcmp( p, buf ) )
422        tr_migrateResume( p, buf );
423
424    return buf;
425}
426
427const char *
428tr_getTorrentsDirectory( void )
429{
430    static char buf[MAX_PATH_LENGTH];
431    static int  init = 0;
432    static const size_t buflen = sizeof(buf);
433    const char * p;
434
435    if( init )
436        return buf;
437
438    p = tr_getPrefsDirectory ();
439
440#if defined(__BEOS__) || defined(WIN32)
441    tr_buildPath( buf, buflen, p, "Torrents", NULL );
442#elif defined( SYS_DARWIN )
443    tr_buildPath( buf, buflen, p, "Torrents", NULL );
444#else
445    tr_buildPath( buf, buflen, p, "torrents", NULL );
446#endif
447
448    tr_mkdirp( buf, 0777 );
449    init = 1;
450    return buf;
451}
Note: See TracBrowser for help on using the repository browser.