OSDN Git Service

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