OSDN Git Service

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