OSDN Git Service

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