OSDN Git Service

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