OSDN Git Service

Change pthread mutex's to be explicitly NORMAL instead of relying on the default...
[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 #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_mutexattr_t mta;
413
414     pthread_mutexattr_init(&mta);
415     pthread_mutexattr_settype(&mta, PTHREAD_MUTEX_NORMAL);
416
417     pthread_mutex_init( &l->mutex, &mta );
418 //#elif defined( SYS_CYGWIN )
419 //    l->mutex = CreateMutex( 0, FALSE, 0 );
420 #endif
421
422     return l;
423 }
424
425 void hb_lock_close( hb_lock_t ** _l )
426 {
427     hb_lock_t * l = *_l;
428
429 #if defined( SYS_BEOS )
430     delete_sem( l->sem );
431 #elif USE_PTHREAD
432     pthread_mutex_destroy( &l->mutex );
433 //#elif defined( SYS_CYGWIN )
434 //    CloseHandle( l->mutex );
435 #endif
436     free( l );
437
438     *_l = NULL;
439 }
440
441 void hb_lock( hb_lock_t * l )
442 {
443 #if defined( SYS_BEOS )
444     acquire_sem( l->sem );
445 #elif USE_PTHREAD
446     pthread_mutex_lock( &l->mutex );
447 //#elif defined( SYS_CYGWIN )
448 //    WaitForSingleObject( l->mutex, INFINITE );
449 #endif
450 }
451
452 void hb_unlock( hb_lock_t * l )
453 {
454 #if defined( SYS_BEOS )
455     release_sem( l->sem );
456 #elif USE_PTHREAD
457     pthread_mutex_unlock( &l->mutex );
458 //#elif defined( SYS_CYGWIN )
459 //    ReleaseMutex( l->mutex );
460 #endif
461 }
462
463 /************************************************************************
464  * Portable condition variable implementation
465  ***********************************************************************/
466 struct hb_cond_s
467 {
468 #if defined( SYS_BEOS )
469     int                 thread;
470 #elif USE_PTHREAD
471     pthread_cond_t      cond;
472 //#elif defined( SYS_CYGWIN )
473 //    HANDLE              event;
474 #endif
475 };
476
477 /************************************************************************
478  * hb_cond_init()
479  * hb_cond_close()
480  * hb_cond_wait()
481  * hb_cond_signal()
482  ************************************************************************
483  * Win9x is not supported by this implementation (SignalObjectAndWait()
484  * only available on Windows 2000/XP).
485  ***********************************************************************/
486 hb_cond_t * hb_cond_init()
487 {
488     hb_cond_t * c = calloc( sizeof( hb_cond_t ), 1 );
489
490 #if defined( SYS_BEOS )
491     c->thread = -1;
492 #elif USE_PTHREAD
493     pthread_cond_init( &c->cond, NULL );
494 //#elif defined( SYS_CYGWIN )
495 //    c->event = CreateEvent( NULL, FALSE, FALSE, NULL );
496 #endif
497
498     return c;
499 }
500
501 void hb_cond_close( hb_cond_t ** _c )
502 {
503     hb_cond_t * c = *_c;
504
505 #if defined( SYS_BEOS )
506 #elif USE_PTHREAD
507     pthread_cond_destroy( &c->cond );
508 //#elif defined( SYS_CYGWIN )
509 //    CloseHandle( c->event );
510 #endif
511     free( c );
512
513     *_c = NULL;
514 }
515
516 void hb_cond_wait( hb_cond_t * c, hb_lock_t * lock )
517 {
518 #if defined( SYS_BEOS )
519     c->thread = find_thread( NULL );
520     release_sem( lock->sem );
521     suspend_thread( c->thread );
522     acquire_sem( lock->sem );
523     c->thread = -1;
524 #elif USE_PTHREAD
525     pthread_cond_wait( &c->cond, &lock->mutex );
526 //#elif defined( SYS_CYGWIN )
527 //    SignalObjectAndWait( lock->mutex, c->event, INFINITE, FALSE );
528 //    WaitForSingleObject( lock->mutex, INFINITE );
529 #endif
530 }
531
532 void hb_cond_signal( hb_cond_t * c )
533 {
534 #if defined( SYS_BEOS )
535     while( c->thread != -1 )
536     {
537         thread_info info;
538         get_thread_info( c->thread, &info );
539         if( info.state == B_THREAD_SUSPENDED )
540         {
541             resume_thread( c->thread );
542             break;
543         }
544         /* Looks like we have been called between hb_cond_wait's
545            release_sem() and suspend_thread() lines. Wait until the
546            thread is actually suspended before we resume it */
547         snooze( 5000 );
548     }
549 #elif USE_PTHREAD
550     pthread_cond_signal( &c->cond );
551 //#elif defined( SYS_CYGWIN )
552 //    PulseEvent( c->event );
553 #endif
554 }
555
556 /************************************************************************
557  * Network
558  ***********************************************************************/
559
560 struct hb_net_s
561 {
562     int socket;
563 };
564
565 hb_net_t * hb_net_open( char * address, int port )
566 {
567     hb_net_t * n = calloc( sizeof( hb_net_t ), 1 );
568
569     struct sockaddr_in   sock;
570     struct hostent     * host;
571
572     /* TODO: find out why this doesn't work on Win32 */
573     if( !( host = gethostbyname( address ) ) )
574     {
575         hb_log( "gethostbyname failed (%s)", address );
576         free( n );
577         return NULL;
578     }
579
580     memset( &sock, 0, sizeof( struct sockaddr_in ) );
581     sock.sin_family = host->h_addrtype;
582     sock.sin_port   = htons( port );
583     memcpy( &sock.sin_addr, host->h_addr, host->h_length );
584
585     if( ( n->socket = socket( host->h_addrtype, SOCK_STREAM, 0 ) ) < 0 )
586     {
587         hb_log( "socket failed" );
588         free( n );
589         return NULL;
590     }
591
592     if( connect( n->socket, (struct sockaddr *) &sock,
593                  sizeof( struct sockaddr_in ) ) < 0 )
594     {
595         hb_log( "connect failed" );
596         free( n );
597         return NULL;
598     }
599
600     return n;
601 }
602
603 int hb_net_send( hb_net_t * n, char * buffer )
604 {
605     return send( n->socket, buffer, strlen( buffer ), 0 );
606 }
607
608 int hb_net_recv( hb_net_t * n, char * buffer, int size )
609 {
610     return recv( n->socket, buffer, size - 1, 0 );
611 }
612
613 void hb_net_close( hb_net_t ** _n )
614 {
615     hb_net_t * n = (hb_net_t *) *_n;
616     close( n->socket );
617     free( n );
618     *_n = NULL;
619 }
620