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