OSDN Git Service

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