OSDN Git Service

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