WinGui: Fix another instance of the Caliburn vs Json.net sillyness where objects...
[HandBrake.git] / libhb / ports.c
blobe93fdb100416f30f8b07840f7178a108104ec6a9
1 /* ports.c
3 Copyright (c) 2003-2015 HandBrake Team
4 This file is part of the HandBrake source code
5 Homepage: <http://handbrake.fr/>.
6 It may be used under the terms of the GNU General Public License v2.
7 For full terms see the file COPYING file or visit http://www.gnu.org/licenses/gpl-2.0.html
8 */
10 #ifdef SYS_MINGW
11 #define _WIN32_WINNT 0x600
12 #endif
14 #ifdef USE_PTHREAD
15 #ifdef SYS_LINUX
16 #define _GNU_SOURCE
17 #include <sched.h>
18 #endif
19 #include <pthread.h>
20 #endif
22 #ifdef SYS_BEOS
23 #include <kernel/OS.h>
24 #endif
26 #if defined(SYS_DARWIN) || defined(SYS_FREEBSD)
27 #include <sys/types.h>
28 #include <sys/sysctl.h>
29 #endif
31 #ifdef SYS_OPENBSD
32 #include <sys/param.h>
33 #include <sys/sysctl.h>
34 #include <machine/cpu.h>
35 #endif
37 #ifdef SYS_MINGW
38 #include <winsock2.h>
39 #include <ws2tcpip.h>
40 #else
41 #include <sys/types.h>
42 #include <sys/socket.h>
43 #include <netdb.h>
44 #include <netinet/in.h>
45 #endif
47 #ifdef SYS_CYGWIN
48 #include <windows.h>
49 #endif
51 #ifdef SYS_MINGW
52 #include <pthread.h>
53 #include <windows.h>
54 #include <wchar.h>
55 #include <mbctype.h>
56 #include <locale.h>
57 #include <shlobj.h>
58 #endif
60 #ifdef SYS_SunOS
61 #include <sys/processor.h>
62 #endif
64 #include <time.h>
65 #include <sys/time.h>
66 #include <ctype.h>
68 #if defined( SYS_LINUX )
69 #include <linux/cdrom.h>
70 #include <fcntl.h>
71 #include <sys/ioctl.h>
72 #elif defined( SYS_OPENBSD )
73 #include <sys/dvdio.h>
74 #include <fcntl.h>
75 #include <sys/ioctl.h>
76 #endif
78 #ifdef __APPLE__
79 #include <IOKit/pwr_mgt/IOPMLib.h>
80 #endif
82 #include <stddef.h>
83 #include <unistd.h>
85 #include "hb.h"
86 #include "libavutil/cpu.h"
88 /************************************************************************
89 * hb_get_date()
90 ************************************************************************
91 * Returns the current date in milliseconds.
92 * On Win32, we implement a gettimeofday emulation here because
93 * libdvdread and libmp4v2 use it without checking.
94 ************************************************************************/
96 #ifdef SYS_CYGWIN
97 struct timezone
101 int gettimeofday( struct timeval * tv, struct timezone * tz )
103 int tick;
104 tick = GetTickCount();
105 tv->tv_sec = tick / 1000;
106 tv->tv_usec = ( tick % 1000 ) * 1000;
107 return 0;
109 #endif
112 // Convert utf8 string to current code page.
113 // The internal string representation in hb is utf8. But some
114 // libraries (libmkv, and mp4v2) expect filenames in the current
115 // code page. So we must convert.
116 char * hb_utf8_to_cp(const char *src)
118 char *dst = NULL;
120 #if defined( SYS_MINGW )
121 int num_chars = MultiByteToWideChar(CP_UTF8, 0, src, -1, NULL, 0);
122 if (num_chars <= 0)
123 return NULL;
124 wchar_t * tmp = calloc(num_chars, sizeof(wchar_t));
125 MultiByteToWideChar(CP_UTF8, 0, src, -1, tmp, num_chars);
126 int len = WideCharToMultiByte(GetACP(), 0, tmp, num_chars, NULL, 0, NULL, NULL);
127 if (len <= 0)
128 return NULL;
129 dst = calloc(len, sizeof(char));
130 WideCharToMultiByte(GetACP(), 0, tmp, num_chars, dst, len, NULL, NULL);
131 free(tmp);
132 #else
133 // Other platforms don't have code pages
134 dst = strdup(src);
135 #endif
137 return dst;
140 int hb_dvd_region(char *device, int *region_mask)
142 #if defined( DVD_LU_SEND_RPC_STATE ) && defined( DVD_AUTH )
143 struct stat st;
144 dvd_authinfo ai;
145 int fd, ret;
147 fd = open( device, O_RDONLY );
148 if ( fd < 0 )
149 return -1;
150 if ( fstat( fd, &st ) < 0 )
152 close( fd );
153 return -1;
155 if ( !( S_ISBLK( st.st_mode ) || S_ISCHR( st.st_mode ) ) )
157 close( fd );
158 return -1;
161 ai.type = DVD_LU_SEND_RPC_STATE;
162 ret = ioctl(fd, DVD_AUTH, &ai);
163 close( fd );
164 if ( ret < 0 )
165 return ret;
167 *region_mask = ai.lrpcs.region_mask;
168 return 0;
169 #else
170 return -1;
171 #endif
174 uint64_t hb_get_date()
176 struct timeval tv;
177 gettimeofday( &tv, NULL );
178 return( (uint64_t) tv.tv_sec * 1000 + (uint64_t) tv.tv_usec / 1000 );
181 uint64_t hb_get_time_us()
183 #ifdef SYS_MINGW
184 static LARGE_INTEGER frequency;
185 LARGE_INTEGER cur_time;
187 if (frequency.QuadPart == 0)
189 QueryPerformanceFrequency(&frequency);
192 QueryPerformanceCounter(&cur_time);
194 return (uint64_t)(1000000 * cur_time.QuadPart / frequency.QuadPart);
195 #else
196 struct timeval tv;
197 gettimeofday(&tv, NULL);
198 return ((uint64_t)tv.tv_sec * 1000000 + (uint64_t)tv.tv_usec);
199 #endif
202 /************************************************************************
203 * hb_snooze()
204 ************************************************************************
205 * Waits <delay> milliseconds.
206 ************************************************************************/
207 void hb_snooze( int delay )
209 if( delay < 1 )
211 return;
213 #if defined( SYS_BEOS )
214 snooze( 1000 * delay );
215 #elif defined( SYS_DARWIN ) || defined( SYS_LINUX ) || defined( SYS_FREEBSD) || defined( SYS_SunOS )
216 usleep( 1000 * delay );
217 #elif defined( SYS_CYGWIN ) || defined( SYS_MINGW )
218 Sleep( delay );
219 #endif
222 /************************************************************************
223 * Get information about the CPU (number of cores, name, platform name)
224 ************************************************************************/
225 static void init_cpu_info();
226 static int init_cpu_count();
227 struct
229 enum hb_cpu_platform platform;
230 const char *name;
231 union
233 char buf[48];
234 uint32_t buf4[12];
236 int count;
237 } hb_cpu_info;
239 int hb_get_cpu_count()
241 return hb_cpu_info.count;
244 int hb_get_cpu_platform()
246 return hb_cpu_info.platform;
249 const char* hb_get_cpu_name()
251 return hb_cpu_info.name;
254 const char* hb_get_cpu_platform_name()
256 switch (hb_cpu_info.platform)
258 // Intel 64 and IA-32 Architectures Software Developer's Manual, Vol. 3C
259 // Table 35-1: CPUID Signature Values of DisplayFamily_DisplayModel
260 case HB_CPU_PLATFORM_INTEL_BNL:
261 return "Intel microarchitecture Bonnell";
262 case HB_CPU_PLATFORM_INTEL_SNB:
263 return "Intel microarchitecture Sandy Bridge";
264 case HB_CPU_PLATFORM_INTEL_IVB:
265 return "Intel microarchitecture Ivy Bridge";
266 case HB_CPU_PLATFORM_INTEL_SLM:
267 return "Intel microarchitecture Silvermont";
268 case HB_CPU_PLATFORM_INTEL_HSW:
269 return "Intel microarchitecture Haswell";
270 case HB_CPU_PLATFORM_INTEL_BDW:
271 return "Intel microarchitecture Broadwell";
272 case HB_CPU_PLATFORM_INTEL_CHT:
273 return "Intel microarchitecture Airmont";
275 default:
276 return NULL;
280 #if ARCH_X86_64
281 # define REG_b "rbx"
282 # define REG_S "rsi"
283 #elif ARCH_X86_32
284 # define REG_b "ebx"
285 # define REG_S "esi"
286 #endif // ARCH_X86_32
288 #if ARCH_X86_64 || ARCH_X86_32
289 #define cpuid(index, eax, ebx, ecx, edx) \
290 __asm__ volatile ( \
291 "mov %%"REG_b", %%"REG_S" \n\t" \
292 "cpuid \n\t" \
293 "xchg %%"REG_b", %%"REG_S \
294 : "=a" (*eax), "=S" (*ebx), "=c" (*ecx), "=d" (*edx) \
295 : "0" (index))
296 #endif // ARCH_X86_64 || ARCH_X86_32
298 static void init_cpu_info()
300 hb_cpu_info.name = NULL;
301 hb_cpu_info.count = init_cpu_count();
302 hb_cpu_info.platform = HB_CPU_PLATFORM_UNSPECIFIED;
304 if (av_get_cpu_flags() & AV_CPU_FLAG_SSE)
306 #if ARCH_X86_64 || ARCH_X86_32
307 int eax, ebx, ecx, edx, family, model;
309 cpuid(1, &eax, &ebx, &ecx, &edx);
310 family = ((eax >> 8) & 0xf) + ((eax >> 20) & 0xff);
311 model = ((eax >> 4) & 0xf) + ((eax >> 12) & 0xf0);
313 // Intel 64 and IA-32 Architectures Software Developer's Manual, Vol. 3C
314 // Table 35-1: CPUID Signature Values of DisplayFamily_DisplayModel
315 switch (family)
317 case 0x06:
319 switch (model)
321 case 0x1C:
322 case 0x26:
323 case 0x27:
324 case 0x35:
325 case 0x36:
326 hb_cpu_info.platform = HB_CPU_PLATFORM_INTEL_BNL;
327 break;
328 case 0x2A:
329 case 0x2D:
330 hb_cpu_info.platform = HB_CPU_PLATFORM_INTEL_SNB;
331 break;
332 case 0x3A:
333 case 0x3E:
334 hb_cpu_info.platform = HB_CPU_PLATFORM_INTEL_IVB;
335 break;
336 case 0x37:
337 case 0x4A:
338 case 0x4D:
339 case 0x5A:
340 case 0x5D:
341 hb_cpu_info.platform = HB_CPU_PLATFORM_INTEL_SLM;
342 break;
343 case 0x3C:
344 case 0x3F:
345 case 0x45:
346 case 0x46:
347 hb_cpu_info.platform = HB_CPU_PLATFORM_INTEL_HSW;
348 break;
349 case 0x3D:
350 case 0x4F:
351 case 0x56:
352 hb_cpu_info.platform = HB_CPU_PLATFORM_INTEL_BDW;
353 break;
354 case 0x4C:
355 hb_cpu_info.platform = HB_CPU_PLATFORM_INTEL_CHT;
356 break;
357 default:
358 break;
360 } break;
362 default:
363 break;
366 // Intel 64 and IA-32 Architectures Software Developer's Manual, Vol. 2A
367 // Figure 3-8: Determination of Support for the Processor Brand String
368 // Table 3-17: Information Returned by CPUID Instruction
369 cpuid(0x80000000, &eax, &ebx, &ecx, &edx);
370 if ((eax & 0x80000004) < 0x80000004)
372 cpuid(0x80000002,
373 &hb_cpu_info.buf4[ 0],
374 &hb_cpu_info.buf4[ 1],
375 &hb_cpu_info.buf4[ 2],
376 &hb_cpu_info.buf4[ 3]);
377 cpuid(0x80000003,
378 &hb_cpu_info.buf4[ 4],
379 &hb_cpu_info.buf4[ 5],
380 &hb_cpu_info.buf4[ 6],
381 &hb_cpu_info.buf4[ 7]);
382 cpuid(0x80000004,
383 &hb_cpu_info.buf4[ 8],
384 &hb_cpu_info.buf4[ 9],
385 &hb_cpu_info.buf4[10],
386 &hb_cpu_info.buf4[11]);
388 hb_cpu_info.name = hb_cpu_info.buf;
389 hb_cpu_info.buf[47] = '\0'; // just in case
391 while (isspace(*hb_cpu_info.name))
393 // skip leading whitespace to prettify
394 hb_cpu_info.name++;
397 #endif // ARCH_X86_64 || ARCH_X86_32
402 * Whenever possible, returns the number of CPUs on the current computer.
403 * Returns 1 otherwise.
405 static int init_cpu_count()
407 int cpu_count = 1;
409 #if defined(SYS_CYGWIN) || defined(SYS_MINGW)
410 SYSTEM_INFO cpuinfo;
411 GetSystemInfo( &cpuinfo );
412 cpu_count = cpuinfo.dwNumberOfProcessors;
414 #elif defined(SYS_LINUX)
415 unsigned int bit;
416 cpu_set_t p_aff;
417 memset( &p_aff, 0, sizeof(p_aff) );
418 sched_getaffinity( 0, sizeof(p_aff), &p_aff );
419 for( cpu_count = 0, bit = 0; bit < sizeof(p_aff); bit++ )
420 cpu_count += (((uint8_t *)&p_aff)[bit / 8] >> (bit % 8)) & 1;
422 #elif defined(SYS_BEOS)
423 system_info info;
424 get_system_info( &info );
425 cpu_count = info.cpu_count;
427 #elif defined(SYS_DARWIN) || defined(SYS_FREEBSD) || defined(SYS_OPENBSD)
428 size_t length = sizeof( cpu_count );
429 #ifdef SYS_OPENBSD
430 int mib[2] = { CTL_HW, HW_NCPU };
431 if( sysctl(mib, 2, &cpu_count, &length, NULL, 0) )
432 #else
433 if( sysctlbyname("hw.ncpu", &cpu_count, &length, NULL, 0) )
434 #endif
436 cpu_count = 1;
439 #elif defined( SYS_SunOS )
441 processorid_t cpumax;
442 int i,j=0;
444 cpumax = sysconf(_SC_CPUID_MAX);
446 for(i = 0; i <= cpumax; i++ )
448 if(p_online(i, P_STATUS) != -1)
450 j++;
453 cpu_count=j;
455 #endif
457 cpu_count = MAX( 1, cpu_count );
458 cpu_count = MIN( cpu_count, 64 );
460 return cpu_count;
463 int hb_platform_init()
465 int result = 0;
467 #if defined(SYS_MINGW) && defined(PTW32_STATIC_LIB)
468 result = !pthread_win32_process_attach_np();
469 if (result)
471 hb_error("pthread_win32_process_attach_np() failed!");
472 return -1;
474 #endif
476 #if defined(_WIN32) || defined(__MINGW32__)
478 * win32 _IOLBF (line-buffering) is the same as _IOFBF (full-buffering).
479 * force it to unbuffered otherwise informative output is not easily parsed.
481 result = setvbuf(stdout, NULL, _IONBF, 0);
482 if (result)
484 hb_error("setvbuf(stdout, NULL, _IONBF, 0) failed!");
485 return -1;
487 result = setvbuf(stderr, NULL, _IONBF, 0);
488 if (result)
490 hb_error("setvbuf(stderr, NULL, _IONBF, 0) failed!");
491 return -1;
493 #endif
495 init_cpu_info();
497 return result;
500 /************************************************************************
501 * Get app data config directory
502 ***********************************************************************/
503 void hb_get_user_config_directory( char path[512] )
505 /* Create the base */
506 #if defined( SYS_CYGWIN ) || defined( SYS_MINGW )
507 #ifndef CSIDL_FLAG_DONT_UNEXPAND
509 * XXX: some old MinGW toolchains don't have SHGetKnownFolderPath.
511 * SHGetFolderPath is deprecated, but this should be no problem in practice.
513 * Note: explicitly call the Unicode/WCHAR function SHGetFolderPathW.
515 WCHAR wide_path[MAX_PATH];
517 if (SHGetFolderPathW(NULL, CSIDL_APPDATA, NULL, SHGFP_TYPE_CURRENT, wide_path) == S_OK &&
518 WideCharToMultiByte(CP_UTF8, 0, wide_path, -1, path, 512, NULL, NULL) != 0)
520 path[511] = 0;
521 return;
523 #else
524 WCHAR *wide_path;
526 if (SHGetKnownFolderPath(&FOLDERID_RoamingAppData, 0, NULL, &wide_path) == S_OK &&
527 WideCharToMultiByte(CP_UTF8, 0, wide_path, -1, path, 512, NULL, NULL) != 0)
529 CoTaskMemFree(wide_path);
530 path[511] = 0;
531 return;
533 else if (wide_path != NULL)
535 CoTaskMemFree(wide_path);
537 #endif // !defined CSIDL_FLAG_DONT_UNEXPAND
538 #elif defined( SYS_LINUX )
539 char *p;
541 if ((p = getenv("XDG_CONFIG_HOME")) != NULL)
543 strncpy(path, p, 511);
544 path[511] = 0;
545 return;
547 else if ((p = getenv("HOME")) != NULL)
549 strncpy(path, p, 511);
550 path[511] = 0;
551 int len = strlen(path);
552 strncpy(path + len, "/.config", 511 - len - 1);
553 path[511] = 0;
554 return;
556 #elif defined( __APPLE__ )
557 if (osx_get_user_config_directory(path) == 0)
559 return;
561 #endif
563 hb_error("Failed to lookup user config directory!");
564 path[0] = 0;
567 /************************************************************************
568 * Get a user config filename for HB
569 ***********************************************************************/
570 void hb_get_user_config_filename( char name[1024], char *fmt, ... )
572 va_list args;
574 hb_get_user_config_directory( name );
575 #if defined( SYS_CYGWIN ) || defined( SYS_MINGW )
576 strcat( name, "\\" );
577 #else
578 strcat( name, "/" );
579 #endif
581 va_start( args, fmt );
582 vsnprintf( &name[strlen(name)], 1024 - strlen(name), fmt, args );
583 va_end( args );
586 /************************************************************************
587 * Get a temporary directory for HB
588 ***********************************************************************/
589 void hb_get_temporary_directory( char path[512] )
591 char base[512];
592 char *p;
594 /* Create the base */
595 #if defined( SYS_CYGWIN ) || defined( SYS_MINGW )
596 int i_size = GetTempPath( 512, base );
597 if( i_size <= 0 || i_size >= 512 )
599 if( getcwd( base, 512 ) == NULL )
600 strcpy( base, "c:" ); /* Bad fallback but ... */
603 /* c:/path/ works like a charm under cygwin(win32?) so use it */
604 while( ( p = strchr( base, '\\' ) ) )
605 *p = '/';
606 #else
607 if( (p = getenv( "TMPDIR" ) ) != NULL ||
608 (p = getenv( "TEMP" ) ) != NULL )
609 strcpy( base, p );
610 else
611 strcpy( base, "/tmp" );
612 #endif
613 /* I prefer to remove evntual last '/' (for cygwin) */
614 if( base[strlen(base)-1] == '/' )
615 base[strlen(base)-1] = '\0';
617 snprintf(path, 512, "%s/hb.%d", base, (int)getpid());
620 /************************************************************************
621 * Get a tempory filename for HB
622 ***********************************************************************/
623 void hb_get_tempory_filename( hb_handle_t * h, char name[1024],
624 char *fmt, ... )
626 va_list args;
628 hb_get_temporary_directory( name );
629 strcat( name, "/" );
631 va_start( args, fmt );
632 vsnprintf( &name[strlen(name)], 1024 - strlen(name), fmt, args );
633 va_end( args );
636 /************************************************************************
637 * hb_stat
638 ************************************************************************
639 * Wrapper to the real stat, needed to handle utf8 filenames on
640 * windows.
641 ***********************************************************************/
642 int hb_stat(const char *path, hb_stat_t *sb)
644 #ifdef SYS_MINGW
645 wchar_t path_utf16[MAX_PATH];
646 if (!MultiByteToWideChar(CP_UTF8, 0, path, -1, path_utf16, MAX_PATH))
647 return -1;
648 return _wstat64( path_utf16, sb );
649 #else
650 return stat(path, sb);
651 #endif
654 /************************************************************************
655 * hb_fopen
656 ************************************************************************
657 * Wrapper to the real fopen, needed to handle utf8 filenames on
658 * windows.
659 ***********************************************************************/
660 FILE * hb_fopen(const char *path, const char *mode)
662 #ifdef SYS_MINGW
663 FILE *f;
664 wchar_t path_utf16[MAX_PATH];
665 wchar_t mode_utf16[16];
666 if (!MultiByteToWideChar(CP_UTF8, 0, path, -1, path_utf16, MAX_PATH))
667 return NULL;
668 if (!MultiByteToWideChar(CP_UTF8, 0, mode, -1, mode_utf16, 16))
669 return NULL;
670 errno_t ret = _wfopen_s(&f, path_utf16, mode_utf16);
671 if (ret)
672 return NULL;
673 return f;
674 #else
675 return fopen(path, mode);
676 #endif
679 HB_DIR* hb_opendir(char *path)
681 #ifdef SYS_MINGW
682 HB_DIR *dir;
683 wchar_t path_utf16[MAX_PATH];
685 if (!MultiByteToWideChar(CP_UTF8, 0, path, -1, path_utf16, MAX_PATH))
686 return NULL;
687 dir = malloc(sizeof(HB_DIR));
688 if (dir == NULL)
689 return NULL;
690 dir->wdir = _wopendir(path_utf16);
691 if (dir->wdir == NULL)
693 free(dir);
694 return NULL;
696 return dir;
697 #else
698 return opendir(path);
699 #endif
702 int hb_closedir(HB_DIR *dir)
704 #ifdef SYS_MINGW
705 int ret;
707 ret = _wclosedir(dir->wdir);
708 free(dir);
709 return ret;
710 #else
711 return closedir(dir);
712 #endif
715 struct dirent * hb_readdir(HB_DIR *dir)
717 #ifdef SYS_MINGW
718 struct _wdirent *entry;
719 entry = _wreaddir(dir->wdir);
720 if (entry == NULL)
721 return NULL;
723 int len = WideCharToMultiByte(CP_UTF8, 0, entry->d_name, -1,
724 dir->entry.d_name, sizeof(dir->entry.d_name),
725 NULL, NULL );
726 dir->entry.d_ino = entry->d_ino;
727 dir->entry.d_reclen = entry->d_reclen;
728 dir->entry.d_namlen = len - 1;
729 return &dir->entry;
730 #else
731 return readdir(dir);
732 #endif
735 void hb_rewinddir(HB_DIR *dir)
737 #ifdef SYS_MINGW
738 _wrewinddir(dir->wdir);
739 #else
740 return rewinddir(dir);
741 #endif
744 char * hb_strr_dir_sep(const char *path)
746 #ifdef SYS_MINGW
747 char *sep = strrchr(path, '/');
748 if (sep == NULL)
749 sep = strrchr(path, '\\');
750 return sep;
751 #else
752 return strrchr(path, '/');
753 #endif
756 /************************************************************************
757 * hb_mkdir
758 ************************************************************************
759 * Wrapper to the real mkdir, needed only because it doesn't take a
760 * second argument on Win32. Grrr.
761 ***********************************************************************/
762 int hb_mkdir(char * path)
764 #ifdef SYS_MINGW
765 wchar_t path_utf16[MAX_PATH];
766 if (!MultiByteToWideChar(CP_UTF8, 0, path, -1, path_utf16, MAX_PATH))
767 return -1;
768 return _wmkdir(path_utf16);
769 #else
770 return mkdir(path, 0755);
771 #endif
774 /************************************************************************
775 * Portable thread implementation
776 ***********************************************************************/
777 struct hb_thread_s
779 char * name;
780 int priority;
781 thread_func_t * function;
782 void * arg;
784 hb_lock_t * lock;
785 int exited;
787 #if defined( SYS_BEOS )
788 thread_id thread;
789 #elif USE_PTHREAD
790 pthread_t thread;
791 //#elif defined( SYS_CYGWIN )
792 // HANDLE thread;
793 #endif
796 /* Get a unique identifier to thread and represent as 64-bit unsigned.
797 * If unsupported, the value 0 is be returned.
798 * Caller should use result only for display/log purposes.
800 static uint64_t hb_thread_to_integer( const hb_thread_t* t )
802 #if defined( USE_PTHREAD )
803 #if defined( SYS_CYGWIN )
804 return (uint64_t)t->thread;
805 #elif defined( _WIN32 ) || defined( __MINGW32__ )
806 #if defined(PTW32_STATIC_LIB)
807 return (uint64_t)(ptrdiff_t)t->thread.p;
808 #else
809 return (uint64_t)t->thread;
810 #endif
811 #elif defined( SYS_DARWIN )
812 return (unsigned long)t->thread;
813 #else
814 return (uint64_t)t->thread;
815 #endif
816 #else
817 return 0;
818 #endif
821 /************************************************************************
822 * hb_thread_func()
823 ************************************************************************
824 * We use it as the root routine for any thread, for two reasons:
825 * + To set the thread priority on OS X (pthread_setschedparam() could
826 * be called from hb_thread_init(), but it's nicer to do it as we
827 * are sure it is done before the real routine starts)
828 * + Get informed when the thread exits, so we know whether
829 * hb_thread_close() will block or not.
830 ***********************************************************************/
831 static void attribute_align_thread hb_thread_func( void * _t )
833 hb_thread_t * t = (hb_thread_t *) _t;
835 #if defined( SYS_DARWIN ) || defined( SYS_FREEBSD )
836 /* Set the thread priority */
837 struct sched_param param;
838 memset( &param, 0, sizeof( struct sched_param ) );
839 param.sched_priority = t->priority;
840 pthread_setschedparam( pthread_self(), SCHED_OTHER, &param );
841 #endif
843 #if defined( SYS_BEOS )
844 signal( SIGINT, SIG_IGN );
845 #endif
847 /* Start the actual routine */
848 t->function( t->arg );
850 /* Inform that the thread can be joined now */
851 hb_deep_log( 2, "thread %"PRIx64" exited (\"%s\")", hb_thread_to_integer( t ), t->name );
852 hb_lock( t->lock );
853 t->exited = 1;
854 hb_unlock( t->lock );
857 /************************************************************************
858 * hb_thread_init()
859 ************************************************************************
860 * name: user-friendly name
861 * function: the thread routine
862 * arg: argument of the routine
863 * priority: HB_LOW_PRIORITY or HB_NORMAL_PRIORITY
864 ***********************************************************************/
865 hb_thread_t * hb_thread_init( const char * name, void (* function)(void *),
866 void * arg, int priority )
868 hb_thread_t * t = calloc( sizeof( hb_thread_t ), 1 );
870 t->name = strdup( name );
871 t->function = function;
872 t->arg = arg;
873 t->priority = priority;
875 t->lock = hb_lock_init();
877 /* Create and start the thread */
878 #if defined( SYS_BEOS )
879 t->thread = spawn_thread( (thread_func) hb_thread_func,
880 name, priority, t );
881 resume_thread( t->thread );
883 #elif USE_PTHREAD
884 pthread_create( &t->thread, NULL,
885 (void * (*)( void * )) hb_thread_func, t );
887 //#elif defined( SYS_CYGWIN )
888 // t->thread = CreateThread( NULL, 0,
889 // (LPTHREAD_START_ROUTINE) hb_thread_func, t, 0, NULL );
891 // /* Maybe use THREAD_PRIORITY_LOWEST instead */
892 // if( priority == HB_LOW_PRIORITY )
893 // SetThreadPriority( GetCurrentThread(), THREAD_PRIORITY_BELOW_NORMAL );
894 #endif
896 hb_deep_log( 2, "thread %"PRIx64" started (\"%s\")", hb_thread_to_integer( t ), t->name );
897 return t;
900 /************************************************************************
901 * hb_thread_close()
902 ************************************************************************
903 * Joins the thread and frees memory.
904 ***********************************************************************/
905 void hb_thread_close( hb_thread_t ** _t )
907 hb_thread_t * t = *_t;
909 /* Join the thread */
910 #if defined( SYS_BEOS )
911 long exit_value;
912 wait_for_thread( t->thread, &exit_value );
914 #elif USE_PTHREAD
915 pthread_join( t->thread, NULL );
917 //#elif defined( SYS_CYGWIN )
918 // WaitForSingleObject( t->thread, INFINITE );
919 #endif
921 hb_deep_log( 2, "thread %"PRIx64" joined (\"%s\")", hb_thread_to_integer( t ), t->name );
923 hb_lock_close( &t->lock );
924 free( t->name );
925 free( t );
926 *_t = NULL;
929 /************************************************************************
930 * hb_thread_has_exited()
931 ************************************************************************
932 * Returns 1 if the thread can be joined right away, 0 otherwise.
933 ***********************************************************************/
934 int hb_thread_has_exited( hb_thread_t * t )
936 int exited;
938 hb_lock( t->lock );
939 exited = t->exited;
940 hb_unlock( t->lock );
942 return exited;
945 /************************************************************************
946 * Portable mutex implementation
947 ***********************************************************************/
948 struct hb_lock_s
950 #if defined( SYS_BEOS )
951 sem_id sem;
952 #elif USE_PTHREAD
953 pthread_mutex_t mutex;
954 //#elif defined( SYS_CYGWIN )
955 // HANDLE mutex;
956 #endif
959 /************************************************************************
960 * hb_lock_init()
961 * hb_lock_close()
962 * hb_lock()
963 * hb_unlock()
964 ************************************************************************
965 * Basic wrappers to OS-specific semaphore or mutex functions.
966 ***********************************************************************/
967 hb_lock_t * hb_lock_init()
969 hb_lock_t * l = calloc( sizeof( hb_lock_t ), 1 );
971 #if defined( SYS_BEOS )
972 l->sem = create_sem( 1, "sem" );
973 #elif USE_PTHREAD
974 pthread_mutexattr_t mta;
976 pthread_mutexattr_init(&mta);
978 #if defined( SYS_CYGWIN ) || defined( SYS_FREEBSD )
979 pthread_mutexattr_settype(&mta, PTHREAD_MUTEX_NORMAL);
980 #endif
982 pthread_mutex_init( &l->mutex, &mta );
983 //#elif defined( SYS_CYGWIN )
984 // l->mutex = CreateMutex( 0, FALSE, 0 );
985 #endif
987 return l;
990 void hb_lock_close( hb_lock_t ** _l )
992 hb_lock_t * l = *_l;
994 #if defined( SYS_BEOS )
995 delete_sem( l->sem );
996 #elif USE_PTHREAD
997 pthread_mutex_destroy( &l->mutex );
998 //#elif defined( SYS_CYGWIN )
999 // CloseHandle( l->mutex );
1000 #endif
1001 free( l );
1003 *_l = NULL;
1006 void hb_lock( hb_lock_t * l )
1008 #if defined( SYS_BEOS )
1009 acquire_sem( l->sem );
1010 #elif USE_PTHREAD
1011 pthread_mutex_lock( &l->mutex );
1012 //#elif defined( SYS_CYGWIN )
1013 // WaitForSingleObject( l->mutex, INFINITE );
1014 #endif
1017 void hb_unlock( hb_lock_t * l )
1019 #if defined( SYS_BEOS )
1020 release_sem( l->sem );
1021 #elif USE_PTHREAD
1022 pthread_mutex_unlock( &l->mutex );
1023 //#elif defined( SYS_CYGWIN )
1024 // ReleaseMutex( l->mutex );
1025 #endif
1028 /************************************************************************
1029 * Portable condition variable implementation
1030 ***********************************************************************/
1031 struct hb_cond_s
1033 #if defined( SYS_BEOS )
1034 int thread;
1035 #elif USE_PTHREAD
1036 pthread_cond_t cond;
1037 //#elif defined( SYS_CYGWIN )
1038 // HANDLE event;
1039 #endif
1042 /************************************************************************
1043 * hb_cond_init()
1044 * hb_cond_close()
1045 * hb_cond_wait()
1046 * hb_cond_signal()
1047 ************************************************************************
1048 * Win9x is not supported by this implementation (SignalObjectAndWait()
1049 * only available on Windows 2000/XP).
1050 ***********************************************************************/
1051 hb_cond_t * hb_cond_init()
1053 hb_cond_t * c = calloc( sizeof( hb_cond_t ), 1 );
1055 if( c == NULL )
1056 return NULL;
1058 #if defined( SYS_BEOS )
1059 c->thread = -1;
1060 #elif USE_PTHREAD
1061 pthread_cond_init( &c->cond, NULL );
1062 //#elif defined( SYS_CYGWIN )
1063 // c->event = CreateEvent( NULL, FALSE, FALSE, NULL );
1064 #endif
1066 return c;
1069 void hb_cond_close( hb_cond_t ** _c )
1071 hb_cond_t * c = *_c;
1073 #if defined( SYS_BEOS )
1074 #elif USE_PTHREAD
1075 pthread_cond_destroy( &c->cond );
1076 //#elif defined( SYS_CYGWIN )
1077 // CloseHandle( c->event );
1078 #endif
1079 free( c );
1081 *_c = NULL;
1084 void hb_cond_wait( hb_cond_t * c, hb_lock_t * lock )
1086 #if defined( SYS_BEOS )
1087 c->thread = find_thread( NULL );
1088 release_sem( lock->sem );
1089 suspend_thread( c->thread );
1090 acquire_sem( lock->sem );
1091 c->thread = -1;
1092 #elif USE_PTHREAD
1093 pthread_cond_wait( &c->cond, &lock->mutex );
1094 //#elif defined( SYS_CYGWIN )
1095 // SignalObjectAndWait( lock->mutex, c->event, INFINITE, FALSE );
1096 // WaitForSingleObject( lock->mutex, INFINITE );
1097 #endif
1100 void hb_clock_gettime( struct timespec *tp )
1102 struct timeval tv;
1104 gettimeofday( &tv, NULL );
1105 tp->tv_sec = tv.tv_sec;
1106 tp->tv_nsec = tv.tv_usec * 1000;
1109 void hb_yield(void)
1111 sched_yield();
1114 void hb_cond_timedwait( hb_cond_t * c, hb_lock_t * lock, int msec )
1116 #if defined( SYS_BEOS )
1117 c->thread = find_thread( NULL );
1118 release_sem( lock->sem );
1119 suspend_thread( c->thread );
1120 acquire_sem( lock->sem );
1121 c->thread = -1;
1122 #elif USE_PTHREAD
1123 struct timespec ts;
1124 hb_clock_gettime(&ts);
1125 ts.tv_nsec += (msec % 1000) * 1000000;
1126 ts.tv_sec += msec / 1000 + (ts.tv_nsec / 1000000000);
1127 ts.tv_nsec %= 1000000000;
1128 pthread_cond_timedwait( &c->cond, &lock->mutex, &ts );
1129 #endif
1132 void hb_cond_signal( hb_cond_t * c )
1134 #if defined( SYS_BEOS )
1135 while( c->thread != -1 )
1137 thread_info info;
1138 get_thread_info( c->thread, &info );
1139 if( info.state == B_THREAD_SUSPENDED )
1141 resume_thread( c->thread );
1142 break;
1144 /* Looks like we have been called between hb_cond_wait's
1145 release_sem() and suspend_thread() lines. Wait until the
1146 thread is actually suspended before we resume it */
1147 snooze( 5000 );
1149 #elif USE_PTHREAD
1150 pthread_cond_signal( &c->cond );
1151 //#elif defined( SYS_CYGWIN )
1152 // PulseEvent( c->event );
1153 #endif
1156 void hb_cond_broadcast( hb_cond_t * c )
1158 #if USE_PTHREAD
1159 pthread_cond_broadcast( &c->cond );
1160 #endif
1163 /************************************************************************
1164 * Network
1165 ***********************************************************************/
1167 struct hb_net_s
1169 int socket;
1172 hb_net_t * hb_net_open( char * address, int port )
1174 hb_net_t * n = calloc( sizeof( hb_net_t ), 1 );
1176 struct sockaddr_in sock;
1177 struct hostent * host;
1179 #ifdef SYS_MINGW
1180 WSADATA wsaData;
1181 int iResult, winsock_init = 0;
1183 // Initialize Winsock
1184 if (!winsock_init)
1186 iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
1187 if (iResult != 0)
1189 hb_log("WSAStartup failed: %d", iResult);
1190 free(n);
1191 return NULL;
1193 winsock_init = 1;
1195 #endif
1197 /* TODO: find out why this doesn't work on Win32 */
1198 if( !( host = gethostbyname( address ) ) )
1200 hb_log( "gethostbyname failed (%s)", address );
1201 free( n );
1202 return NULL;
1205 memset( &sock, 0, sizeof( struct sockaddr_in ) );
1206 sock.sin_family = host->h_addrtype;
1207 sock.sin_port = htons( port );
1208 memcpy( &sock.sin_addr, host->h_addr, host->h_length );
1210 if( ( n->socket = socket( host->h_addrtype, SOCK_STREAM, 0 ) ) < 0 )
1212 hb_log( "socket failed" );
1213 free( n );
1214 return NULL;
1217 if( connect( n->socket, (struct sockaddr *) &sock,
1218 sizeof( struct sockaddr_in ) ) < 0 )
1220 hb_log( "connect failed" );
1221 free( n );
1222 return NULL;
1225 return n;
1228 int hb_net_send( hb_net_t * n, char * buffer )
1230 return send( n->socket, buffer, strlen( buffer ), 0 );
1233 int hb_net_recv( hb_net_t * n, char * buffer, int size )
1235 return recv( n->socket, buffer, size - 1, 0 );
1238 void hb_net_close( hb_net_t ** _n )
1240 hb_net_t * n = (hb_net_t *) *_n;
1241 close( n->socket );
1242 free( n );
1243 *_n = NULL;
1246 /************************************************************************
1247 * OS Sleep Allow / Prevent
1248 ***********************************************************************/
1250 #ifdef __APPLE__
1251 // 128 chars limit for IOPMAssertionCreateWithName
1252 static CFStringRef reasonForActivity =
1253 CFSTR("HandBrake is currently scanning and/or encoding");
1254 #endif
1256 void* hb_system_sleep_opaque_init()
1258 void *opaque = NULL;
1259 #ifdef __APPLE__
1260 opaque = calloc(sizeof(IOPMAssertionID), 1);
1261 if (opaque == NULL)
1263 hb_error("hb_system_sleep: failed to allocate opaque");
1264 return NULL;
1267 IOPMAssertionID *assertionID = (IOPMAssertionID*)opaque;
1268 *assertionID = -1;
1269 #endif
1270 return opaque;
1273 void hb_system_sleep_opaque_close(void **opaque)
1275 if (*opaque != NULL)
1277 hb_system_sleep_private_enable(*opaque);
1279 #ifdef __APPLE__
1280 if (*opaque != NULL)
1282 IOPMAssertionID *assertionID = (IOPMAssertionID*)*opaque;
1283 free(assertionID);
1285 #endif
1286 *opaque = NULL;
1289 void hb_system_sleep_private_enable(void *opaque)
1291 #ifdef __APPLE__
1292 if (opaque == NULL)
1294 hb_error("hb_system_sleep: opaque is NULL");
1297 IOPMAssertionID *assertionID = (IOPMAssertionID*)opaque;
1298 if (*assertionID == -1)
1300 // nothing to do
1301 return;
1304 IOReturn success = IOPMAssertionRelease(*assertionID);
1305 if (success == kIOReturnSuccess)
1307 hb_deep_log(3,
1308 "hb_system_sleep: assertion %d released, sleep allowed",
1309 *assertionID);
1310 *assertionID = -1;
1312 else
1314 hb_log("hb_system_sleep: failed to allow system sleep");
1316 #endif
1319 void hb_system_sleep_private_disable(void *opaque)
1321 #ifdef __APPLE__
1322 if (opaque == NULL)
1324 hb_error("hb_system_sleep: opaque is NULL");
1327 IOPMAssertionID *assertionID = (IOPMAssertionID*)opaque;
1328 if (*assertionID != -1)
1330 // nothing to do
1331 return;
1334 IOReturn success = IOPMAssertionCreateWithName(kIOPMAssertionTypeNoIdleSleep,
1335 kIOPMAssertionLevelOn,
1336 reasonForActivity,
1337 assertionID);
1338 if (success == kIOReturnSuccess)
1340 hb_deep_log(3,
1341 "hb_system_sleep: assertion %d created, sleep prevented",
1342 *assertionID);
1344 else
1346 hb_log("hb_system_sleep: failed to prevent system sleep");
1348 #endif