OSDN Git Service

This patch adds mingw32 cross-compilation support to HandBrake trunk to
[handbrake-jp/handbrake-jp-git.git] / libhb / ports.c
1 /* $Id: ports.c,v 1.15 2005/10/15 18:05:03 titer Exp $
2
3    This file is part of the HandBrake source code.
4    Homepage: <http://handbrake.fr/>.
5    It may be used under the terms of the GNU General Public License. */
6
7 #ifdef USE_PTHREAD
8 #ifdef SYS_LINUX
9 #define _GNU_SOURCE
10 #include <sched.h>
11 #endif
12 #include <pthread.h>
13 #endif
14
15 #ifdef SYS_BEOS
16 #include <kernel/OS.h>
17 #endif
18
19 #if defined(SYS_DARWIN) || defined(SYS_FREEBSD)
20 #include <sys/types.h>
21 #include <sys/sysctl.h>
22 #endif
23
24 #ifdef SYS_OPENBSD
25 #include <sys/param.h>
26 #include <sys/sysctl.h>
27 #include <machine/cpu.h>
28 #endif
29
30 #ifdef SYS_CYGWIN
31 #include <windows.h>
32 #endif
33
34 #ifdef SYS_MINGW
35 #include <pthread.h>
36 #include <windows.h>
37 #endif
38
39 #ifdef SYS_SunOS
40 #include <sys/processor.h>
41 #endif
42
43 #include <time.h>
44 #include <sys/time.h>
45
46
47 #ifdef SYS_MINGW
48 #include <winsock2.h>
49 #include <ws2tcpip.h>
50 #else
51 #include <sys/types.h>
52 #include <sys/socket.h>
53 #include <netdb.h>
54 #include <netinet/in.h>
55 #endif
56
57 #include "hb.h"
58
59 /************************************************************************
60  * hb_get_date()
61  ************************************************************************
62  * Returns the current date in milliseconds.
63  * On Win32, we implement a gettimeofday emulation here because
64  * libdvdread and libmp4v2 use it without checking.
65  ************************************************************************/
66 /*
67 #ifdef SYS_CYGWIN
68 struct timezone
69 {
70 };
71
72 int gettimeofday( struct timeval * tv, struct timezone * tz )
73 {
74     int tick;
75     tick        = GetTickCount();
76     tv->tv_sec  = tick / 1000;
77     tv->tv_usec = ( tick % 1000 ) * 1000;
78     return 0;
79 }
80 #endif
81 */
82
83 uint64_t hb_get_date()
84 {
85     struct timeval tv;
86     gettimeofday( &tv, NULL );
87     return( (uint64_t) tv.tv_sec * 1000 + (uint64_t) tv.tv_usec / 1000 );
88 }
89
90 /************************************************************************
91  * hb_snooze()
92  ************************************************************************
93  * Waits <delay> milliseconds.
94  ************************************************************************/
95 void hb_snooze( int delay )
96 {
97     if( delay < 1 )
98     {
99         return;
100     }
101 #if defined( SYS_BEOS )
102     snooze( 1000 * delay );
103 #elif defined( SYS_DARWIN ) || defined( SYS_LINUX ) || defined( SYS_FREEBSD) || defined( SYS_SunOS )
104     usleep( 1000 * delay );
105 #elif defined( SYS_CYGWIN ) || defined( SYS_MINGW )
106     Sleep( delay );
107 #endif
108 }
109
110 /************************************************************************
111  * hb_get_cpu_count()
112  ************************************************************************
113  * Whenever possible, returns the number of CPUs on the current
114  * computer. Returns 1 otherwise.
115  * The detection is actually only performed on the first call.
116  ************************************************************************/
117 int hb_get_cpu_count()
118 {
119     static int cpu_count = 0;
120
121     if( cpu_count )
122     {
123         return cpu_count;
124     }
125     cpu_count = 1;
126
127 #if defined(SYS_CYGWIN) || defined(SYS_MINGW)
128     SYSTEM_INFO cpuinfo;
129     GetSystemInfo( &cpuinfo );
130     cpu_count = cpuinfo.dwNumberOfProcessors;
131
132 #elif defined(SYS_LINUX)
133     unsigned int bit;
134     cpu_set_t p_aff;
135     memset( &p_aff, 0, sizeof(p_aff) );
136     sched_getaffinity( 0, sizeof(p_aff), &p_aff );
137     for( cpu_count = 0, bit = 0; bit < sizeof(p_aff); bit++ )
138          cpu_count += (((uint8_t *)&p_aff)[bit / 8] >> (bit % 8)) & 1;
139
140 #elif defined(SYS_BEOS)
141     system_info info;
142     get_system_info( &info );
143     cpu_count = info.cpu_count;
144
145 #elif defined(SYS_DARWIN) || defined(SYS_FREEBSD) || defined(SYS_OPENBSD)
146     size_t length = sizeof( cpu_count );
147 #ifdef SYS_OPENBSD
148     int mib[2] = { CTL_HW, HW_NCPU };
149     if( sysctl(mib, 2, &cpu_count, &length, NULL, 0) )
150 #else
151     if( sysctlbyname("hw.ncpu", &cpu_count, &length, NULL, 0) )
152 #endif
153     {
154         cpu_count = 1;
155     }
156
157 #elif defined( SYS_SunOS )
158     {
159         processorid_t cpumax;
160         int i,j=0;
161
162         cpumax = sysconf(_SC_CPUID_MAX);
163
164         for(i = 0; i <= cpumax; i++ )
165         {
166             if(p_online(i, P_STATUS) != -1)
167             {
168                 j++;
169             }
170         }
171         cpu_count=j;
172     }
173 #endif
174
175     cpu_count = MAX( 1, cpu_count );
176     cpu_count = MIN( cpu_count, 8 );
177
178     return cpu_count;
179 }
180
181 /************************************************************************
182  * Get a tempory directory for HB
183  ***********************************************************************/
184 void hb_get_tempory_directory( hb_handle_t * h, char path[512] )
185 {
186     char base[512];
187
188     /* Create the base */
189 #if defined( SYS_CYGWIN ) || defined( SYS_MINGW )
190     char *p;
191     int i_size = GetTempPath( 512, base );
192     if( i_size <= 0 || i_size >= 512 )
193     {
194         if( getcwd( base, 512 ) == NULL )
195             strcpy( base, "c:" ); /* Bad fallback but ... */
196     }
197
198     /* c:/path/ works like a charm under cygwin(win32?) so use it */
199     while( ( p = strchr( base, '\\' ) ) )
200         *p = '/';
201 #else
202     strcpy( base, "/tmp" );
203 #endif
204     /* I prefer to remove evntual last '/' (for cygwin) */
205     if( base[strlen(base)-1] == '/' )
206         base[strlen(base)-1] = '\0';
207
208     snprintf( path, 512, "%s/hb.%d", base, hb_get_pid( h ) );
209 }
210
211 /************************************************************************
212  * Get a tempory filename for HB
213  ***********************************************************************/
214 void hb_get_tempory_filename( hb_handle_t * h, char name[1024],
215                               char *fmt, ... )
216 {
217     va_list args;
218
219     hb_get_tempory_directory( h, name );
220     strcat( name, "/" );
221
222     va_start( args, fmt );
223     vsnprintf( &name[strlen(name)], 1024 - strlen(name), fmt, args );
224     va_end( args );
225 }
226
227 /************************************************************************
228  * hb_mkdir
229  ************************************************************************
230  * Wrapper to the real mkdir, needed only because it doesn't take a
231  * second argument on Win32. Grrr.
232  ***********************************************************************/
233 void hb_mkdir( char * name )
234 {
235 #ifdef SYS_MINGW
236     mkdir( name );
237 #else
238     mkdir( name, 0755 );
239 #endif
240 }
241
242 /************************************************************************
243  * Portable thread implementation
244  ***********************************************************************/
245 struct hb_thread_s
246 {
247     char       * name;
248     int          priority;
249     void      (* function) ( void * );
250     void       * arg;
251
252     hb_lock_t  * lock;
253     int          exited;
254
255 #if defined( SYS_BEOS )
256     thread_id    thread;
257 #elif USE_PTHREAD
258     pthread_t    thread;
259 //#elif defined( SYS_CYGWIN )
260 //    HANDLE       thread;
261 #endif
262 };
263
264 /************************************************************************
265  * hb_thread_func()
266  ************************************************************************
267  * We use it as the root routine for any thread, for two reasons:
268  *  + To set the thread priority on OS X (pthread_setschedparam() could
269  *    be called from hb_thread_init(), but it's nicer to do it as we
270  *    are sure it is done before the real routine starts)
271  *  + Get informed when the thread exits, so we know whether
272  *    hb_thread_close() will block or not.
273  ***********************************************************************/
274 static void hb_thread_func( void * _t )
275 {
276     hb_thread_t * t = (hb_thread_t *) _t;
277
278 #if defined( SYS_DARWIN )
279     /* Set the thread priority */
280     struct sched_param param;
281     memset( &param, 0, sizeof( struct sched_param ) );
282     param.sched_priority = t->priority;
283     pthread_setschedparam( pthread_self(), SCHED_OTHER, &param );
284 #endif
285
286 #if defined( SYS_BEOS )
287     signal( SIGINT, SIG_IGN );
288 #endif
289
290     /* Start the actual routine */
291     t->function( t->arg );
292
293     /* Inform that the thread can be joined now */
294     hb_deep_log( 2, "thread %x exited (\"%s\")", t->thread, t->name );
295     hb_lock( t->lock );
296     t->exited = 1;
297     hb_unlock( t->lock );
298 }
299
300 /************************************************************************
301  * hb_thread_init()
302  ************************************************************************
303  * name:     user-friendly name
304  * function: the thread routine
305  * arg:      argument of the routine
306  * priority: HB_LOW_PRIORITY or HB_NORMAL_PRIORITY
307  ***********************************************************************/
308 hb_thread_t * hb_thread_init( char * name, void (* function)(void *),
309                               void * arg, int priority )
310 {
311     hb_thread_t * t = calloc( sizeof( hb_thread_t ), 1 );
312
313     t->name     = strdup( name );
314     t->function = function;
315     t->arg      = arg;
316     t->priority = priority;
317
318     t->lock     = hb_lock_init();
319
320     /* Create and start the thread */
321 #if defined( SYS_BEOS )
322     t->thread = spawn_thread( (thread_func) hb_thread_func,
323                               name, priority, t );
324     resume_thread( t->thread );
325
326 #elif USE_PTHREAD
327     pthread_create( &t->thread, NULL,
328                     (void * (*)( void * )) hb_thread_func, t );
329
330 //#elif defined( SYS_CYGWIN )
331 //    t->thread = CreateThread( NULL, 0,
332 //        (LPTHREAD_START_ROUTINE) hb_thread_func, t, 0, NULL );
333 //
334 //    /* Maybe use THREAD_PRIORITY_LOWEST instead */
335 //    if( priority == HB_LOW_PRIORITY )
336 //        SetThreadPriority( GetCurrentThread(), THREAD_PRIORITY_BELOW_NORMAL );
337 #endif
338
339     hb_deep_log( 2, "thread %x started (\"%s\")", t->thread, t->name );
340     return t;
341 }
342
343 /************************************************************************
344  * hb_thread_close()
345  ************************************************************************
346  * Joins the thread and frees memory.
347  ***********************************************************************/
348 void hb_thread_close( hb_thread_t ** _t )
349 {
350     hb_thread_t * t = *_t;
351
352     /* Join the thread */
353 #if defined( SYS_BEOS )
354     long exit_value;
355     wait_for_thread( t->thread, &exit_value );
356
357 #elif USE_PTHREAD
358     pthread_join( t->thread, NULL );
359
360 //#elif defined( SYS_CYGWIN )
361 //    WaitForSingleObject( t->thread, INFINITE );
362 #endif
363
364     hb_deep_log( 2, "thread %x joined (\"%s\")",
365             t->thread, t->name );
366
367     hb_lock_close( &t->lock );
368     free( t->name );
369     free( t );
370     *_t = NULL;
371 }
372
373 /************************************************************************
374  * hb_thread_has_exited()
375  ************************************************************************
376  * Returns 1 if the thread can be joined right away, 0 otherwise.
377  ***********************************************************************/
378 int hb_thread_has_exited( hb_thread_t * t )
379 {
380     int exited;
381
382     hb_lock( t->lock );
383     exited = t->exited;
384     hb_unlock( t->lock );
385
386     return exited;
387 }
388
389 /************************************************************************
390  * Portable mutex implementation
391  ***********************************************************************/
392 struct hb_lock_s
393 {
394 #if defined( SYS_BEOS )
395     sem_id          sem;
396 #elif USE_PTHREAD
397     pthread_mutex_t mutex;
398 //#elif defined( SYS_CYGWIN )
399 //    HANDLE          mutex;
400 #endif
401 };
402
403 /************************************************************************
404  * hb_lock_init()
405  * hb_lock_close()
406  * hb_lock()
407  * hb_unlock()
408  ************************************************************************
409  * Basic wrappers to OS-specific semaphore or mutex functions.
410  ***********************************************************************/
411 hb_lock_t * hb_lock_init()
412 {
413     hb_lock_t * l = calloc( sizeof( hb_lock_t ), 1 );
414
415 #if defined( SYS_BEOS )
416     l->sem = create_sem( 1, "sem" );
417 #elif USE_PTHREAD
418     pthread_mutexattr_t mta;
419
420     pthread_mutexattr_init(&mta);
421
422 #if defined( SYS_CYGWIN )
423     pthread_mutexattr_settype(&mta, PTHREAD_MUTEX_NORMAL);
424 #endif
425
426     pthread_mutex_init( &l->mutex, &mta );
427 //#elif defined( SYS_CYGWIN )
428 //    l->mutex = CreateMutex( 0, FALSE, 0 );
429 #endif
430
431     return l;
432 }
433
434 void hb_lock_close( hb_lock_t ** _l )
435 {
436     hb_lock_t * l = *_l;
437
438 #if defined( SYS_BEOS )
439     delete_sem( l->sem );
440 #elif USE_PTHREAD
441     pthread_mutex_destroy( &l->mutex );
442 //#elif defined( SYS_CYGWIN )
443 //    CloseHandle( l->mutex );
444 #endif
445     free( l );
446
447     *_l = NULL;
448 }
449
450 void hb_lock( hb_lock_t * l )
451 {
452 #if defined( SYS_BEOS )
453     acquire_sem( l->sem );
454 #elif USE_PTHREAD
455     pthread_mutex_lock( &l->mutex );
456 //#elif defined( SYS_CYGWIN )
457 //    WaitForSingleObject( l->mutex, INFINITE );
458 #endif
459 }
460
461 void hb_unlock( hb_lock_t * l )
462 {
463 #if defined( SYS_BEOS )
464     release_sem( l->sem );
465 #elif USE_PTHREAD
466     pthread_mutex_unlock( &l->mutex );
467 //#elif defined( SYS_CYGWIN )
468 //    ReleaseMutex( l->mutex );
469 #endif
470 }
471
472 /************************************************************************
473  * Portable condition variable implementation
474  ***********************************************************************/
475 struct hb_cond_s
476 {
477 #if defined( SYS_BEOS )
478     int                 thread;
479 #elif USE_PTHREAD
480     pthread_cond_t      cond;
481 //#elif defined( SYS_CYGWIN )
482 //    HANDLE              event;
483 #endif
484 };
485
486 /************************************************************************
487  * hb_cond_init()
488  * hb_cond_close()
489  * hb_cond_wait()
490  * hb_cond_signal()
491  ************************************************************************
492  * Win9x is not supported by this implementation (SignalObjectAndWait()
493  * only available on Windows 2000/XP).
494  ***********************************************************************/
495 hb_cond_t * hb_cond_init()
496 {
497     hb_cond_t * c = calloc( sizeof( hb_cond_t ), 1 );
498
499 #if defined( SYS_BEOS )
500     c->thread = -1;
501 #elif USE_PTHREAD
502     pthread_cond_init( &c->cond, NULL );
503 //#elif defined( SYS_CYGWIN )
504 //    c->event = CreateEvent( NULL, FALSE, FALSE, NULL );
505 #endif
506
507     return c;
508 }
509
510 void hb_cond_close( hb_cond_t ** _c )
511 {
512     hb_cond_t * c = *_c;
513
514 #if defined( SYS_BEOS )
515 #elif USE_PTHREAD
516     pthread_cond_destroy( &c->cond );
517 //#elif defined( SYS_CYGWIN )
518 //    CloseHandle( c->event );
519 #endif
520     free( c );
521
522     *_c = NULL;
523 }
524
525 void hb_cond_wait( hb_cond_t * c, hb_lock_t * lock )
526 {
527 #if defined( SYS_BEOS )
528     c->thread = find_thread( NULL );
529     release_sem( lock->sem );
530     suspend_thread( c->thread );
531     acquire_sem( lock->sem );
532     c->thread = -1;
533 #elif USE_PTHREAD
534     pthread_cond_wait( &c->cond, &lock->mutex );
535 //#elif defined( SYS_CYGWIN )
536 //    SignalObjectAndWait( lock->mutex, c->event, INFINITE, FALSE );
537 //    WaitForSingleObject( lock->mutex, INFINITE );
538 #endif
539 }
540
541 void hb_cond_signal( hb_cond_t * c )
542 {
543 #if defined( SYS_BEOS )
544     while( c->thread != -1 )
545     {
546         thread_info info;
547         get_thread_info( c->thread, &info );
548         if( info.state == B_THREAD_SUSPENDED )
549         {
550             resume_thread( c->thread );
551             break;
552         }
553         /* Looks like we have been called between hb_cond_wait's
554            release_sem() and suspend_thread() lines. Wait until the
555            thread is actually suspended before we resume it */
556         snooze( 5000 );
557     }
558 #elif USE_PTHREAD
559     pthread_cond_signal( &c->cond );
560 //#elif defined( SYS_CYGWIN )
561 //    PulseEvent( c->event );
562 #endif
563 }
564
565 /************************************************************************
566  * Network
567  ***********************************************************************/
568
569 struct hb_net_s
570 {
571     int socket;
572 };
573
574 hb_net_t * hb_net_open( char * address, int port )
575 {
576     hb_net_t * n = calloc( sizeof( hb_net_t ), 1 );
577
578     struct sockaddr_in   sock;
579     struct hostent     * host;
580
581     /* TODO: find out why this doesn't work on Win32 */
582     if( !( host = gethostbyname( address ) ) )
583     {
584         hb_log( "gethostbyname failed (%s)", address );
585         free( n );
586         return NULL;
587     }
588
589     memset( &sock, 0, sizeof( struct sockaddr_in ) );
590     sock.sin_family = host->h_addrtype;
591     sock.sin_port   = htons( port );
592     memcpy( &sock.sin_addr, host->h_addr, host->h_length );
593
594     if( ( n->socket = socket( host->h_addrtype, SOCK_STREAM, 0 ) ) < 0 )
595     {
596         hb_log( "socket failed" );
597         free( n );
598         return NULL;
599     }
600
601     if( connect( n->socket, (struct sockaddr *) &sock,
602                  sizeof( struct sockaddr_in ) ) < 0 )
603     {
604         hb_log( "connect failed" );
605         free( n );
606         return NULL;
607     }
608
609     return n;
610 }
611
612 int hb_net_send( hb_net_t * n, char * buffer )
613 {
614     return send( n->socket, buffer, strlen( buffer ), 0 );
615 }
616
617 int hb_net_recv( hb_net_t * n, char * buffer, int size )
618 {
619     return recv( n->socket, buffer, size - 1, 0 );
620 }
621
622 void hb_net_close( hb_net_t ** _n )
623 {
624     hb_net_t * n = (hb_net_t *) *_n;
625     close( n->socket );
626     free( n );
627     *_n = NULL;
628 }
629