1 /* $Id: ports.c,v 1.15 2005/10/15 18:05:03 titer Exp $
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. */
16 #include <kernel/OS.h>
19 #if defined(SYS_DARWIN) || defined(SYS_FREEBSD)
20 #include <sys/types.h>
21 #include <sys/sysctl.h>
25 #include <sys/param.h>
26 #include <sys/sysctl.h>
27 #include <machine/cpu.h>
40 #include <sys/processor.h>
51 #include <sys/types.h>
52 #include <sys/socket.h>
54 #include <netinet/in.h>
57 #if defined( SYS_LINUX )
58 #include <linux/cdrom.h>
60 #include <sys/ioctl.h>
61 #elif defined( SYS_OPENBSD )
62 #include <sys/dvdio.h>
64 #include <sys/ioctl.h>
72 /************************************************************************
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 ************************************************************************/
85 int gettimeofday( struct timeval * tv, struct timezone * tz )
88 tick = GetTickCount();
89 tv->tv_sec = tick / 1000;
90 tv->tv_usec = ( tick % 1000 ) * 1000;
96 int hb_dvd_region(char *device, int *region_mask)
98 #if defined( DVD_LU_SEND_RPC_STATE ) && defined( DVD_AUTH )
103 fd = open( device, O_RDONLY );
106 if ( fstat( fd, &st ) < 0 )
111 if ( !( S_ISBLK( st.st_mode ) || S_ISCHR( st.st_mode ) ) )
117 ai.type = DVD_LU_SEND_RPC_STATE;
118 ret = ioctl(fd, DVD_AUTH, &ai);
123 *region_mask = ai.lrpcs.region_mask;
130 uint64_t hb_get_date()
133 gettimeofday( &tv, NULL );
134 return( (uint64_t) tv.tv_sec * 1000 + (uint64_t) tv.tv_usec / 1000 );
137 /************************************************************************
139 ************************************************************************
140 * Waits <delay> milliseconds.
141 ************************************************************************/
142 void hb_snooze( int delay )
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 )
157 /************************************************************************
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()
166 static int cpu_count = 0;
174 #if defined(SYS_CYGWIN) || defined(SYS_MINGW)
176 GetSystemInfo( &cpuinfo );
177 cpu_count = cpuinfo.dwNumberOfProcessors;
179 #elif defined(SYS_LINUX)
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;
187 #elif defined(SYS_BEOS)
189 get_system_info( &info );
190 cpu_count = info.cpu_count;
192 #elif defined(SYS_DARWIN) || defined(SYS_FREEBSD) || defined(SYS_OPENBSD)
193 size_t length = sizeof( cpu_count );
195 int mib[2] = { CTL_HW, HW_NCPU };
196 if( sysctl(mib, 2, &cpu_count, &length, NULL, 0) )
198 if( sysctlbyname("hw.ncpu", &cpu_count, &length, NULL, 0) )
204 #elif defined( SYS_SunOS )
206 processorid_t cpumax;
209 cpumax = sysconf(_SC_CPUID_MAX);
211 for(i = 0; i <= cpumax; i++ )
213 if(p_online(i, P_STATUS) != -1)
222 cpu_count = MAX( 1, cpu_count );
223 cpu_count = MIN( cpu_count, 8 );
228 /************************************************************************
229 * Get a temporary directory for HB
230 ***********************************************************************/
231 void hb_get_temporary_directory( char path[512] )
235 /* Create the base */
236 #if defined( SYS_CYGWIN ) || defined( SYS_MINGW )
238 int i_size = GetTempPath( 512, base );
239 if( i_size <= 0 || i_size >= 512 )
241 if( getcwd( base, 512 ) == NULL )
242 strcpy( base, "c:" ); /* Bad fallback but ... */
245 /* c:/path/ works like a charm under cygwin(win32?) so use it */
246 while( ( p = strchr( base, '\\' ) ) )
249 strcpy( base, "/tmp" );
251 /* I prefer to remove evntual last '/' (for cygwin) */
252 if( base[strlen(base)-1] == '/' )
253 base[strlen(base)-1] = '\0';
255 snprintf( path, 512, "%s/hb.%d", base, getpid() );
258 /************************************************************************
259 * Get a tempory filename for HB
260 ***********************************************************************/
261 void hb_get_tempory_filename( hb_handle_t * h, char name[1024],
266 hb_get_temporary_directory( name );
269 va_start( args, fmt );
270 vsnprintf( &name[strlen(name)], 1024 - strlen(name), fmt, args );
274 /************************************************************************
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 )
289 /************************************************************************
290 * Portable thread implementation
291 ***********************************************************************/
296 void (* function) ( void * );
302 #if defined( SYS_BEOS )
306 //#elif defined( SYS_CYGWIN )
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.
315 static uint64_t hb_thread_to_integer( const hb_thread_t* t )
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;
325 return (uint64_t)t->thread;
332 /************************************************************************
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 )
344 hb_thread_t * t = (hb_thread_t *) _t;
346 #if defined( SYS_DARWIN )
347 /* Set the thread priority */
348 struct sched_param param;
349 memset( ¶m, 0, sizeof( struct sched_param ) );
350 param.sched_priority = t->priority;
351 pthread_setschedparam( pthread_self(), SCHED_OTHER, ¶m );
354 #if defined( SYS_BEOS )
355 signal( SIGINT, SIG_IGN );
358 /* Start the actual routine */
359 t->function( t->arg );
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 );
365 hb_unlock( t->lock );
368 /************************************************************************
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 )
379 hb_thread_t * t = calloc( sizeof( hb_thread_t ), 1 );
381 t->name = strdup( name );
382 t->function = function;
384 t->priority = priority;
386 t->lock = hb_lock_init();
388 /* Create and start the thread */
389 #if defined( SYS_BEOS )
390 t->thread = spawn_thread( (thread_func) hb_thread_func,
392 resume_thread( t->thread );
395 pthread_create( &t->thread, NULL,
396 (void * (*)( void * )) hb_thread_func, t );
398 //#elif defined( SYS_CYGWIN )
399 // t->thread = CreateThread( NULL, 0,
400 // (LPTHREAD_START_ROUTINE) hb_thread_func, t, 0, NULL );
402 // /* Maybe use THREAD_PRIORITY_LOWEST instead */
403 // if( priority == HB_LOW_PRIORITY )
404 // SetThreadPriority( GetCurrentThread(), THREAD_PRIORITY_BELOW_NORMAL );
407 hb_deep_log( 2, "thread %"PRIx64" started (\"%s\")", hb_thread_to_integer( t ), t->name );
411 /************************************************************************
413 ************************************************************************
414 * Joins the thread and frees memory.
415 ***********************************************************************/
416 void hb_thread_close( hb_thread_t ** _t )
418 hb_thread_t * t = *_t;
420 /* Join the thread */
421 #if defined( SYS_BEOS )
423 wait_for_thread( t->thread, &exit_value );
426 pthread_join( t->thread, NULL );
428 //#elif defined( SYS_CYGWIN )
429 // WaitForSingleObject( t->thread, INFINITE );
432 hb_deep_log( 2, "thread %"PRIx64" joined (\"%s\")", hb_thread_to_integer( t ), t->name );
434 hb_lock_close( &t->lock );
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 )
451 hb_unlock( t->lock );
456 /************************************************************************
457 * Portable mutex implementation
458 ***********************************************************************/
461 #if defined( SYS_BEOS )
464 pthread_mutex_t mutex;
465 //#elif defined( SYS_CYGWIN )
470 /************************************************************************
475 ************************************************************************
476 * Basic wrappers to OS-specific semaphore or mutex functions.
477 ***********************************************************************/
478 hb_lock_t * hb_lock_init()
480 hb_lock_t * l = calloc( sizeof( hb_lock_t ), 1 );
482 #if defined( SYS_BEOS )
483 l->sem = create_sem( 1, "sem" );
485 pthread_mutexattr_t mta;
487 pthread_mutexattr_init(&mta);
489 #if defined( SYS_CYGWIN )
490 pthread_mutexattr_settype(&mta, PTHREAD_MUTEX_NORMAL);
493 pthread_mutex_init( &l->mutex, &mta );
494 //#elif defined( SYS_CYGWIN )
495 // l->mutex = CreateMutex( 0, FALSE, 0 );
501 void hb_lock_close( hb_lock_t ** _l )
505 #if defined( SYS_BEOS )
506 delete_sem( l->sem );
508 pthread_mutex_destroy( &l->mutex );
509 //#elif defined( SYS_CYGWIN )
510 // CloseHandle( l->mutex );
517 void hb_lock( hb_lock_t * l )
519 #if defined( SYS_BEOS )
520 acquire_sem( l->sem );
522 pthread_mutex_lock( &l->mutex );
523 //#elif defined( SYS_CYGWIN )
524 // WaitForSingleObject( l->mutex, INFINITE );
528 void hb_unlock( hb_lock_t * l )
530 #if defined( SYS_BEOS )
531 release_sem( l->sem );
533 pthread_mutex_unlock( &l->mutex );
534 //#elif defined( SYS_CYGWIN )
535 // ReleaseMutex( l->mutex );
539 /************************************************************************
540 * Portable condition variable implementation
541 ***********************************************************************/
544 #if defined( SYS_BEOS )
548 //#elif defined( SYS_CYGWIN )
553 /************************************************************************
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()
564 hb_cond_t * c = calloc( sizeof( hb_cond_t ), 1 );
566 #if defined( SYS_BEOS )
569 pthread_cond_init( &c->cond, NULL );
570 //#elif defined( SYS_CYGWIN )
571 // c->event = CreateEvent( NULL, FALSE, FALSE, NULL );
577 void hb_cond_close( hb_cond_t ** _c )
581 #if defined( SYS_BEOS )
583 pthread_cond_destroy( &c->cond );
584 //#elif defined( SYS_CYGWIN )
585 // CloseHandle( c->event );
592 void hb_cond_wait( hb_cond_t * c, hb_lock_t * lock )
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 );
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 );
608 void hb_clock_gettime( struct timespec *tp )
614 gettimeofday( &tv, NULL );
615 tp->tv_sec = tv.tv_sec;
616 tp->tv_nsec = tv.tv_usec * 1000;
619 void hb_cond_timedwait( hb_cond_t * c, hb_lock_t * lock, int msec )
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 );
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 );
637 void hb_cond_signal( hb_cond_t * c )
639 #if defined( SYS_BEOS )
640 while( c->thread != -1 )
643 get_thread_info( c->thread, &info );
644 if( info.state == B_THREAD_SUSPENDED )
646 resume_thread( c->thread );
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 */
655 pthread_cond_signal( &c->cond );
656 //#elif defined( SYS_CYGWIN )
657 // PulseEvent( c->event );
661 void hb_cond_broadcast( hb_cond_t * c )
664 pthread_cond_broadcast( &c->cond );
668 /************************************************************************
670 ***********************************************************************/
677 hb_net_t * hb_net_open( char * address, int port )
679 hb_net_t * n = calloc( sizeof( hb_net_t ), 1 );
681 struct sockaddr_in sock;
682 struct hostent * host;
686 int iResult, winsock_init = 0;
688 // Initialize Winsock
691 iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
694 hb_log("WSAStartup failed: %d", iResult);
701 /* TODO: find out why this doesn't work on Win32 */
702 if( !( host = gethostbyname( address ) ) )
704 hb_log( "gethostbyname failed (%s)", address );
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 );
714 if( ( n->socket = socket( host->h_addrtype, SOCK_STREAM, 0 ) ) < 0 )
716 hb_log( "socket failed" );
721 if( connect( n->socket, (struct sockaddr *) &sock,
722 sizeof( struct sockaddr_in ) ) < 0 )
724 hb_log( "connect failed" );
732 int hb_net_send( hb_net_t * n, char * buffer )
734 return send( n->socket, buffer, strlen( buffer ), 0 );
737 int hb_net_recv( hb_net_t * n, char * buffer, int size )
739 return recv( n->socket, buffer, size - 1, 0 );
742 void hb_net_close( hb_net_t ** _n )
744 hb_net_t * n = (hb_net_t *) *_n;