diff --git a/.gitignore b/.gitignore index 048417b7d..ff66464d9 100755 --- a/.gitignore +++ b/.gitignore @@ -37,6 +37,9 @@ external/* # Documentation docs/api client/X11/xfreerdp.1 +client/X11/xfreerdp.1.xml +client/X11/xfreerdp-channels.1.xml +client/X11/xfreerdp-examples.1.xml # Mac OS X .DS_Store diff --git a/CMakeLists.txt b/CMakeLists.txt index 445e81fd3..5822b82fa 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -313,6 +313,10 @@ set(NPP_FEATURE_TYPE "OPTIONAL") set(NPP_FEATURE_PURPOSE "performance") set(NPP_FEATURE_DESCRIPTION "NVIDIA Performance Primitives library") +set(JPEG_FEATURE_TYPE "OPTIONAL") +set(JPEG_FEATURE_PURPOSE "codec") +set(JPEG_FEATURE_DESCRIPTION "use JPEG library") + if(WIN32) set(X11_FEATURE_TYPE "DISABLED") set(ZLIB_FEATURE_TYPE "DISABLED") @@ -372,6 +376,8 @@ find_feature(PCSC ${PCSC_FEATURE_TYPE} ${PCSC_FEATURE_PURPOSE} ${PCSC_FEATURE_DE find_feature(FFmpeg ${FFMPEG_FEATURE_TYPE} ${FFMPEG_FEATURE_PURPOSE} ${FFMPEG_FEATURE_DESCRIPTION}) find_feature(Gstreamer ${GSTREAMER_FEATURE_TYPE} ${GSTREAMER_FEATURE_PURPOSE} ${GSTREAMER_FEATURE_DESCRIPTION}) +find_feature(JPEG ${JPEG_FEATURE_TYPE} ${JPEG_FEATURE_PURPOSE} ${JPEG_FEATURE_DESCRIPTION}) + if(TARGET_ARCH MATCHES "x86|x64") if (NOT APPLE) # Intel Performance Primitives @@ -400,12 +406,12 @@ set(FREERDP_ADDIN_PATH "${FREERDP_PLUGIN_PATH}") set(FREERDP_EXTENSION_PATH "${CMAKE_INSTALL_FULL_LIBDIR}/freerdp/extensions") # Include directories -include_directories(${CMAKE_CURRENT_SOURCE_DIR}) +include_directories(${CMAKE_CURRENT_BINARY_DIR}) include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include) # Configure files add_definitions("-DHAVE_CONFIG_H") -configure_file(${CMAKE_CURRENT_SOURCE_DIR}/config.h.in ${CMAKE_CURRENT_SOURCE_DIR}/config.h) +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/config.h.in ${CMAKE_CURRENT_BINARY_DIR}/config.h) # RPATH configuration set(CMAKE_SKIP_BUILD_RPATH FALSE) @@ -430,8 +436,8 @@ if(BUILD_TESTING) endif() # WinPR -set(WINPR_INCLUDE_DIR "${CMAKE_SOURCE_DIR}/winpr/include") -include_directories(${WINPR_INCLUDE_DIR}) +include_directories("${CMAKE_SOURCE_DIR}/winpr/include") +include_directories("${CMAKE_BINARY_DIR}/winpr/include") add_subdirectory(winpr) diff --git a/channels/client/CMakeLists.txt b/channels/client/CMakeLists.txt index 6aa60777a..fc42466bb 100644 --- a/channels/client/CMakeLists.txt +++ b/channels/client/CMakeLists.txt @@ -19,16 +19,16 @@ set(MODULE_NAME "freerdp-channels-client") set(MODULE_PREFIX "FREERDP_CHANNELS_CLIENT") set(${MODULE_PREFIX}_SRCS - tables.c - tables.h - addin.c - addin.h - init.c - init.h - open.c - open.h - channels.c - channels.h) + ${CMAKE_CURRENT_BINARY_DIR}/tables.c + ${CMAKE_CURRENT_SOURCE_DIR}/tables.h + ${CMAKE_CURRENT_SOURCE_DIR}/addin.c + ${CMAKE_CURRENT_SOURCE_DIR}/addin.h + ${CMAKE_CURRENT_SOURCE_DIR}/init.c + ${CMAKE_CURRENT_SOURCE_DIR}/init.h + ${CMAKE_CURRENT_SOURCE_DIR}/open.c + ${CMAKE_CURRENT_SOURCE_DIR}/open.h + ${CMAKE_CURRENT_SOURCE_DIR}/channels.c + ${CMAKE_CURRENT_SOURCE_DIR}/channels.h) list(REMOVE_DUPLICATES CHANNEL_STATIC_CLIENT_ENTRIES) @@ -96,7 +96,7 @@ foreach(STATIC_MODULE ${CHANNEL_STATIC_CLIENT_MODULES}) endforeach() set(CLIENT_STATIC_ADDIN_TABLE "${CLIENT_STATIC_ADDIN_TABLE}\n\t{ NULL, NULL, NULL }\n};") -configure_file(${CMAKE_CURRENT_SOURCE_DIR}/tables.c.in ${CMAKE_CURRENT_SOURCE_DIR}/tables.c) +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/tables.c.in ${CMAKE_CURRENT_BINARY_DIR}/tables.c) set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS MONOLITHIC ${MONOLITHIC_BUILD} diff --git a/channels/cliprdr/client/cliprdr_format.c b/channels/cliprdr/client/cliprdr_format.c index 023bbf8e1..426475a64 100644 --- a/channels/cliprdr/client/cliprdr_format.c +++ b/channels/cliprdr/client/cliprdr_format.c @@ -87,14 +87,15 @@ void cliprdr_process_format_list_event(cliprdrPlugin* cliprdr, RDP_CB_FORMAT_LIS if (!cliprdr->use_long_format_names) name_length = 32; - Stream_EnsureRemainingCapacity(body, Stream_Capacity(body) + 4 + name_length); + Stream_EnsureRemainingCapacity(body, 4 + name_length); Stream_Write_UINT32(body, cb_event->formats[i]); Stream_Write(body, name, name_length); } - s = cliprdr_packet_new(CB_FORMAT_LIST, 0, Stream_Capacity(body)); - Stream_Write(s, Stream_Buffer(body), Stream_Capacity(body)); + Stream_SealLength(body); + s = cliprdr_packet_new(CB_FORMAT_LIST, 0, Stream_Length(body)); + Stream_Write(s, Stream_Buffer(body), Stream_Length(body)); Stream_Free(body, TRUE); } @@ -290,16 +291,16 @@ void cliprdr_process_format_list(cliprdrPlugin* cliprdr, wStream* s, UINT32 data void cliprdr_process_format_list_response(cliprdrPlugin* cliprdr, wStream* s, UINT32 dataLen, UINT16 msgFlags) { - /* where is this documented? */ -#if 0 + /* http://msdn.microsoft.com/en-us/library/hh872154.aspx */ wMessage* event; if ((msgFlags & CB_RESPONSE_FAIL) != 0) { - event = freerdp_event_new(RDP_EVENT_CLASS_CLIPRDR, RDP_EVENT_TYPE_CB_MONITOR_READY, NULL, NULL); + /* In case of an error the clipboard will not be synchronized with the server. + * Post this event to restart format negociation and data transfer. */ + event = freerdp_event_new(CliprdrChannel_Class, CliprdrChannel_MonitorReady, NULL, NULL); svc_plugin_send_event((rdpSvcPlugin*) cliprdr, event); } -#endif } void cliprdr_process_format_data_request(cliprdrPlugin* cliprdr, wStream* s, UINT32 dataLen, UINT16 msgFlags) diff --git a/channels/parallel/client/parallel_main.c b/channels/parallel/client/parallel_main.c index 6e35c1ee9..16bf4bbb0 100644 --- a/channels/parallel/client/parallel_main.c +++ b/channels/parallel/client/parallel_main.c @@ -286,6 +286,7 @@ static void parallel_free(DEVICE* device) MessageQueue_PostQuit(parallel->queue, 0); WaitForSingleObject(parallel->thread, INFINITE); + Stream_Free(parallel->device.data, TRUE); MessageQueue_Free(parallel->queue); CloseHandle(parallel->thread); diff --git a/channels/printer/client/printer_main.c b/channels/printer/client/printer_main.c index 89e2ffb81..3826b7c3a 100644 --- a/channels/printer/client/printer_main.c +++ b/channels/printer/client/printer_main.c @@ -179,13 +179,16 @@ static void* printer_thread_func(void* arg) { IRP* irp; PRINTER_DEVICE* printer_dev = (PRINTER_DEVICE*) arg; + HANDLE obj[] = {printer_dev->event, printer_dev->stopEvent}; while (1) { - WaitForSingleObject(printer_dev->event, INFINITE); + DWORD rc = WaitForMultipleObjects(2, obj, FALSE, INFINITE); - if (WaitForSingleObject(printer_dev->stopEvent, 0) == WAIT_OBJECT_0) + if (rc == WAIT_OBJECT_0 + 1) break; + else if( rc != WAIT_OBJECT_0 ) + continue; ResetEvent(printer_dev->event); diff --git a/channels/serial/client/serial_main.c b/channels/serial/client/serial_main.c index fb6b07915..5f8002008 100644 --- a/channels/serial/client/serial_main.c +++ b/channels/serial/client/serial_main.c @@ -63,7 +63,9 @@ struct _SERIAL_DEVICE SERIAL_TTY* tty; HANDLE thread; + HANDLE mthread; HANDLE stopEvent; + HANDLE newEvent; wQueue* queue; LIST* pending_irps; @@ -80,6 +82,7 @@ static void serial_abort_single_io(SERIAL_DEVICE* serial, UINT32 file_id, UINT32 static void serial_check_for_events(SERIAL_DEVICE* serial); static void serial_handle_async_irp(SERIAL_DEVICE* serial, IRP* irp); static BOOL serial_check_fds(SERIAL_DEVICE* serial); +static void* serial_thread_mfunc(void* arg); static void serial_process_irp_create(SERIAL_DEVICE* serial, IRP* irp) { @@ -113,6 +116,18 @@ static void serial_process_irp_create(SERIAL_DEVICE* serial, IRP* irp) else { serial->tty = tty; + + serial_abort_single_io(serial, serial->timeout_id, SERIAL_ABORT_IO_NONE, + STATUS_CANCELLED); + serial_abort_single_io(serial, serial->timeout_id, SERIAL_ABORT_IO_READ, + STATUS_CANCELLED); + serial_abort_single_io(serial, serial->timeout_id, SERIAL_ABORT_IO_WRITE, + STATUS_CANCELLED); + + serial->mthread = CreateThread(NULL, 0, + (LPTHREAD_START_ROUTINE) serial_thread_mfunc, (void*) serial, + 0, NULL); + DEBUG_SVC("%s(%d) created.", serial->path, FileId); } @@ -139,6 +154,11 @@ static void serial_process_irp_close(SERIAL_DEVICE* serial, IRP* irp) { DEBUG_SVC("%s(%d) closed.", serial->path, tty->id); + TerminateThread(serial->mthread, 0); + WaitForSingleObject(serial->mthread, INFINITE); + CloseHandle(serial->mthread); + serial->mthread = NULL; + serial_tty_free(tty); serial->tty = NULL; } @@ -318,37 +338,67 @@ static void serial_process_irp(SERIAL_DEVICE* serial, IRP* irp) serial_check_for_events(serial); } +/* This thread is used as a workaround for the missing serial event + * support in WaitForMultipleObjects. + * It monitors the terminal for events and posts it in a supported + * form that WaitForMultipleObjects can use it. */ +void* serial_thread_mfunc(void* arg) +{ + SERIAL_DEVICE* serial = (SERIAL_DEVICE*)arg; + + while(1) + { + int sl; + fd_set rd; + + if(!serial->tty || serial->tty->fd <= 0) + { + DEBUG_WARN("Monitor thread still running, but no terminal opened!"); + sleep(1); + } + else + { + FD_ZERO(&rd); + FD_SET(serial->tty->fd, &rd); + sl = select(serial->tty->fd + 1, &rd, NULL, NULL, NULL); + if( sl > 0 ) + SetEvent(serial->newEvent); + } + } + + return NULL; +} + static void* serial_thread_func(void* arg) { IRP* irp; DWORD status; SERIAL_DEVICE* serial = (SERIAL_DEVICE*)arg; + HANDLE ev[] = {serial->stopEvent, Queue_Event(serial->queue), serial->newEvent}; while (1) { - if (WaitForSingleObject(serial->stopEvent, 0) == WAIT_OBJECT_0) + status = WaitForMultipleObjects(3, ev, FALSE, INFINITE); + + if (WAIT_OBJECT_0 == status) break; - - status = WaitForSingleObject(Queue_Event(serial->queue), 10); - - if ((status != WAIT_OBJECT_0) && (status != WAIT_TIMEOUT)) - break; - - serial->nfds = 1; - FD_ZERO(&serial->read_fds); - FD_ZERO(&serial->write_fds); - - serial->tv.tv_sec = 1; - serial->tv.tv_usec = 0; - serial->select_timeout = 0; - - if (status == WAIT_OBJECT_0) + else if (status == WAIT_OBJECT_0 + 1) { + FD_ZERO(&serial->read_fds); + FD_ZERO(&serial->write_fds); + + serial->tv.tv_sec = 0; + serial->tv.tv_usec = 0; + serial->select_timeout = 0; + if ((irp = (IRP*) Queue_Dequeue(serial->queue))) serial_process_irp(serial, irp); } + else if (status == WAIT_OBJECT_0 + 2) + ResetEvent(serial->newEvent); - serial_check_fds(serial); + if(serial->tty) + serial_check_fds(serial); } return NULL; @@ -367,10 +417,25 @@ static void serial_free(DEVICE* device) DEBUG_SVC("freeing device"); + /* Stop thread */ SetEvent(serial->stopEvent); + if(serial->mthread) + { + TerminateThread(serial->mthread, 0); + WaitForSingleObject(serial->mthread, INFINITE); + CloseHandle(serial->mthread); + } + WaitForSingleObject(serial->thread, INFINITE); - /* TODO: free lists */ + serial_tty_free(serial->tty); + /* Clean up resources */ + Stream_Free(serial->device.data, TRUE); + Queue_Free(serial->queue); + list_free(serial->pending_irps); + CloseHandle(serial->stopEvent); + CloseHandle(serial->newEvent); + CloseHandle(serial->thread); free(serial); } @@ -383,6 +448,11 @@ static void serial_abort_single_io(SERIAL_DEVICE* serial, UINT32 file_id, UINT32 DEBUG_SVC("[in] pending size %d", list_size(serial->pending_irps)); tty = serial->tty; + if(!tty) + { + DEBUG_WARN("tty = %p", tty); + return; + } switch (abort_io) { @@ -433,6 +503,11 @@ static void serial_check_for_events(SERIAL_DEVICE* serial) SERIAL_TTY* tty; tty = serial->tty; + if(!tty) + { + DEBUG_WARN("tty = %p", tty); + return; + } DEBUG_SVC("[in] pending size %d", list_size(serial->pending_irps)); @@ -478,6 +553,11 @@ void serial_get_timeouts(SERIAL_DEVICE* serial, IRP* irp, UINT32* timeout, UINT3 DEBUG_SVC("length read %u", Length); tty = serial->tty; + if(!tty) + { + DEBUG_WARN("tty = %p", tty); + return; + } *timeout = (tty->read_total_timeout_multiplier * Length) + tty->read_total_timeout_constant; *interval_timeout = tty->read_interval_timeout; @@ -492,6 +572,11 @@ static void serial_handle_async_irp(SERIAL_DEVICE* serial, IRP* irp) SERIAL_TTY* tty; tty = serial->tty; + if(!tty) + { + DEBUG_WARN("tty = %p", tty); + return; + } switch (irp->MajorFunction) { @@ -542,6 +627,11 @@ static void __serial_check_fds(SERIAL_DEVICE* serial) ZeroMemory(&serial->tv, sizeof(struct timeval)); tty = serial->tty; + if(!tty) + { + DEBUG_WARN("tty = %p", tty); + return; + } /* scan every pending */ irp = list_peek(serial->pending_irps); @@ -604,6 +694,11 @@ static void serial_set_fds(SERIAL_DEVICE* serial) DEBUG_SVC("[in] pending size %d", list_size(serial->pending_irps)); tty = serial->tty; + if(!tty) + { + DEBUG_WARN("tty = %p", tty); + return; + } irp = (IRP*) list_peek(serial->pending_irps); while (irp) @@ -636,6 +731,13 @@ static BOOL serial_check_fds(SERIAL_DEVICE* serial) if (list_size(serial->pending_irps) == 0) return 1; + FD_ZERO(&serial->read_fds); + FD_ZERO(&serial->write_fds); + + serial->tv.tv_sec = 0; + serial->tv.tv_usec = 0; + serial->select_timeout = 0; + serial_set_fds(serial); DEBUG_SVC("waiting %lu %lu", serial->tv.tv_sec, serial->tv.tv_usec); @@ -702,10 +804,13 @@ int DeviceServiceEntry(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints) serial->pending_irps = list_new(); serial->stopEvent = CreateEvent(NULL, TRUE, FALSE, NULL); + serial->newEvent = CreateEvent(NULL, TRUE, FALSE, NULL); pEntryPoints->RegisterDevice(pEntryPoints->devman, (DEVICE*) serial); - serial->thread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) serial_thread_func, (void*) serial, 0, NULL); + serial->thread = CreateThread(NULL, 0, + (LPTHREAD_START_ROUTINE) serial_thread_func, (void*) serial, 0, NULL); + serial->mthread = NULL; } return 0; diff --git a/channels/serial/client/serial_tty.c b/channels/serial/client/serial_tty.c index 23445b2ca..95bf375fe 100644 --- a/channels/serial/client/serial_tty.c +++ b/channels/serial/client/serial_tty.c @@ -412,7 +412,11 @@ BOOL serial_tty_read(SERIAL_TTY* tty, BYTE* buffer, UINT32* Length) status = read(tty->fd, buffer, *Length); if (status < 0) + { + DEBUG_WARN("failed with %zd, errno=[%d] %s\n", + status, errno, strerror(errno)); return FALSE; + } tty->event_txempty = status; *Length = status; @@ -456,6 +460,9 @@ void serial_tty_free(SERIAL_TTY* tty) { DEBUG_SVC("in"); + if(!tty) + return; + if (tty->fd >= 0) { if (tty->pold_termios) diff --git a/channels/smartcard/client/smartcard_main.c b/channels/smartcard/client/smartcard_main.c index fa4dd0b3d..855df3ff0 100644 --- a/channels/smartcard/client/smartcard_main.c +++ b/channels/smartcard/client/smartcard_main.c @@ -44,8 +44,7 @@ static void smartcard_free(DEVICE* dev) SMARTCARD_DEVICE* smartcard = (SMARTCARD_DEVICE*) dev; SetEvent(smartcard->stopEvent); - CloseHandle(smartcard->thread); - CloseHandle(smartcard->irpEvent); + WaitForSingleObject(smartcard->thread, INFINITE); while ((irp = (IRP*) InterlockedPopEntrySList(smartcard->pIrpList)) != NULL) irp->Discard(irp); @@ -55,8 +54,14 @@ static void smartcard_free(DEVICE* dev) /* Begin TS Client defect workaround. */ while ((CompletionIdInfo = (COMPLETIONIDINFO*) list_dequeue(smartcard->CompletionIds)) != NULL) - free(CompletionIdInfo); + free(CompletionIdInfo); + CloseHandle(smartcard->thread); + CloseHandle(smartcard->irpEvent); + CloseHandle(smartcard->stopEvent); + CloseHandle(smartcard->CompletionIdsMutex); + + Stream_Free(smartcard->device.data, TRUE); list_free(smartcard->CompletionIds); /* End TS Client defect workaround. */ @@ -119,13 +124,16 @@ static void smartcard_process_irp_thread_func(SMARTCARD_IRP_WORKER* irpWorker) static void* smartcard_thread_func(void* arg) { SMARTCARD_DEVICE* smartcard = (SMARTCARD_DEVICE*) arg; + HANDLE ev[] = {smartcard->irpEvent, smartcard->stopEvent}; while (1) { - WaitForSingleObject(smartcard->irpEvent, INFINITE); + DWORD status = WaitForMultipleObjects(2, ev, FALSE, INFINITE); - if (WaitForSingleObject(smartcard->stopEvent, 0) == WAIT_OBJECT_0) + if (status == WAIT_OBJECT_0 + 1) break; + else if(status != WAIT_OBJECT_0) + continue; ResetEvent(smartcard->irpEvent); smartcard_process_irp_list(smartcard); diff --git a/channels/urbdrc/client/CMakeLists.txt b/channels/urbdrc/client/CMakeLists.txt index 53391f100..736097122 100644 --- a/channels/urbdrc/client/CMakeLists.txt +++ b/channels/urbdrc/client/CMakeLists.txt @@ -31,6 +31,10 @@ set(${MODULE_PREFIX}_SRCS include_directories(..) +find_package(UDev REQUIRED) +find_package(UUID REQUIRED) +find_package(DbusGlib REQUIRED) + add_channel_client_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} TRUE "DVCPluginEntry") set_target_properties(${MODULE_NAME} PROPERTIES PREFIX "") @@ -38,9 +42,9 @@ set_target_properties(${MODULE_NAME} PROPERTIES PREFIX "") #set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} libusb-devman) set(${MODULE_PREFIX}_LIBS - dbus-glib-1 - udev - uuid) + ${DBUS_GLIB_LIBRARIES} + ${UDEV_LIBRARIES} + ${UUID_LIBRARIES}) set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS MONOLITHIC ${MONOLITHIC_BUILD} diff --git a/channels/urbdrc/client/libusb/CMakeLists.txt b/channels/urbdrc/client/libusb/CMakeLists.txt index 0f66539da..47688b9b0 100644 --- a/channels/urbdrc/client/libusb/CMakeLists.txt +++ b/channels/urbdrc/client/libusb/CMakeLists.txt @@ -27,6 +27,8 @@ set(${MODULE_PREFIX}_SRCS include_directories(..) +find_package(libusb-1.0 REQUIRED) + add_channel_client_subsystem_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} "" TRUE "") set_target_properties(${MODULE_NAME} PROPERTIES PREFIX "") @@ -35,9 +37,10 @@ set(${MODULE_PREFIX}_LIBS ${CMAKE_THREAD_LIBS_INIT}) set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} - dbus-glib-1 - usb-1.0 - udev) + ${DBUS_GLIB_LIBRARIES} + ${UUID_LIBRARIES} + ${LIBUSB_1_LIBRARIES} + ) set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS MONOLITHIC ${MONOLITHIC_BUILD} diff --git a/client/X11/.gitignore b/client/X11/.gitignore new file mode 100644 index 000000000..de7ef2209 --- /dev/null +++ b/client/X11/.gitignore @@ -0,0 +1,2 @@ +*.xml +generate_argument_docbook diff --git a/client/X11/CMakeLists.txt b/client/X11/CMakeLists.txt index 56dd96bdb..50dd118ec 100644 --- a/client/X11/CMakeLists.txt +++ b/client/X11/CMakeLists.txt @@ -18,7 +18,7 @@ set(MODULE_NAME "xfreerdp-client") set(MODULE_PREFIX "FREERDP_CLIENT_X11_CONTROL") -include(FindXmlto) +include(FindDocBookXSL) include_directories(${X11_INCLUDE_DIRS}) set(${MODULE_PREFIX}_SRCS @@ -65,18 +65,55 @@ set(${MODULE_PREFIX}_LIBS ${CMAKE_DL_LIBS}) if(WITH_MANPAGES) - if(XMLTO_FOUND) + find_program( XSLTPROC_EXECUTABLE NAMES xsltproc) + + if(DOCBOOKXSL_FOUND AND XSLTPROC_EXECUTABLE) + + # We need the variable ${MAN_TODAY} to contain the current date in ISO + # format to replace it in the configure_file step. + include(today) + + TODAY(MAN_TODAY) + + configure_file(xfreerdp.1.xml.in xfreerdp.1.xml @ONLY IMMEDIATE) + + add_executable(generate_argument_docbook generate_argument_docbook.c) + + set(GAD_LIBS freerdp-client) + + set_complex_link_libraries(VARIABLE GAD_LIBS MONOLITHIC ${MONOLITHIC_BUILD} + MODULE winpr + MODULES winpr-utils) + + set_complex_link_libraries(VARIABLE GAD_LIBS MONOLITHIC ${MONOLITHIC_BUILD} + MODULE freerdp + MODULES freerdp-core freerdp-utils) + + message(WARNING "GAD_LIBS: ${GAD_LIBS}") + + target_link_libraries(generate_argument_docbook ${GAD_LIBS}) + add_custom_command(OUTPUT xfreerdp.1 - COMMAND ${XMLTO_EXECUTABLE} man ${CMAKE_CURRENT_SOURCE_DIR}/xfreerdp.1.xml - DEPENDS xfreerdp.1.xml) + COMMAND generate_argument_docbook + COMMAND ${CMAKE_COMMAND} -E copy + ${CMAKE_CURRENT_SOURCE_DIR}/xfreerdp-channels.1.xml ${CMAKE_CURRENT_BINARY_DIR} + COMMAND ${CMAKE_COMMAND} -E copy + ${CMAKE_CURRENT_SOURCE_DIR}/xfreerdp-examples.1.xml ${CMAKE_CURRENT_BINARY_DIR} + COMMAND ${XSLTPROC_EXECUTABLE} ${DOCBOOKXSL_DIR}/manpages/docbook.xsl xfreerdp.1.xml + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} + DEPENDS + ${CMAKE_CURRENT_BINARY_DIR}/xfreerdp.1.xml + ${CMAKE_CURRENT_SOURCE_DIR}/xfreerdp-examples.1.xml + ${CMAKE_CURRENT_SOURCE_DIR}/xfreerdp-channels.1.xml + generate_argument_docbook) add_custom_target(xfreerdp.manpage ALL DEPENDS xfreerdp.1) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/xfreerdp.1 DESTINATION share/man/man1) - else(XMLTO_FOUND) - message(WARNING "WITH_MANPAGES was set, but xmlto was not found. man-pages will not be installed") - endif(XMLTO_FOUND) + else() + message(WARNING "WITH_MANPAGES was set, but xsltproc was not found. man-pages will not be installed") + endif() endif(WITH_MANPAGES) set(XSHM_FEATURE_TYPE "REQUIRED") diff --git a/client/X11/generate_argument_docbook.c b/client/X11/generate_argument_docbook.c new file mode 100644 index 000000000..0c1da21a8 --- /dev/null +++ b/client/X11/generate_argument_docbook.c @@ -0,0 +1,177 @@ + +#include +#include +#include + +#include + +/* We need to include the command line c file to get access to + * the argument struct. */ +#include "../common/cmdline.c" + +LPSTR tmp = NULL; + +LPCSTR tr_esc_str(LPCSTR arg) +{ + size_t cs = 0, x, ds; + size_t s; + + if( NULL == arg ) + return NULL; + + s = strlen(arg); + + /* Find trailing whitespaces */ + while( (s > 0) && isspace(arg[s-1])) + s--; + + /* Prepare a initial buffer with the size of the result string. */ + tmp = malloc(s * sizeof(LPCSTR)); + if( NULL == tmp ) + { + fprintf(stderr, "Could not allocate string buffer."); + exit(-2); + } + + /* Copy character for character and check, if it is necessary to escape. */ + ds = s + 1; + for(x=0; x': + ds += 3; + tmp = realloc(tmp, ds * sizeof(LPCSTR)); + if( NULL == tmp ) + { + fprintf(stderr, "Could not reallocate string buffer."); + exit(-4); + } + tmp[cs++] = '&'; + tmp[cs++] = 'g'; + tmp[cs++] = 't'; + tmp[cs++] = ';'; + break; + case '\'': + ds += 5; + tmp = realloc(tmp, ds * sizeof(LPCSTR)); + if( NULL == tmp ) + { + fprintf(stderr, "Could not reallocate string buffer."); + exit(-5); + } + tmp[cs++] = '&'; + tmp[cs++] = 'a'; + tmp[cs++] = 'p'; + tmp[cs++] = 'o'; + tmp[cs++] = 's'; + tmp[cs++] = ';'; + break; + case '"': + ds += 5; + tmp = realloc(tmp, ds * sizeof(LPCSTR)); + if( NULL == tmp ) + { + fprintf(stderr, "Could not reallocate string buffer."); + exit(-6); + } + tmp[cs++] = '&'; + tmp[cs++] = 'q'; + tmp[cs++] = 'u'; + tmp[cs++] = 'o'; + tmp[cs++] = 't'; + tmp[cs++] = ';'; + break; + case '&': + ds += 4; + tmp = realloc(tmp, ds * sizeof(LPCSTR)); + if( NULL == tmp ) + { + fprintf(stderr, "Could not reallocate string buffer."); + exit(-7); + } + tmp[cs++] = '&'; + tmp[cs++] = 'a'; + tmp[cs++] = 'm'; + tmp[cs++] = 'p'; + tmp[cs++] = ';'; + break; + default: + tmp[cs++] = arg[x]; + break; + } + + /* Assure, the string is '\0' terminated. */ + tmp[ds-1] = '\0'; + } + + return tmp; +} + +int main(int argc, char *argv[]) +{ + size_t elements = sizeof(args)/sizeof(args[0]); + size_t x; + const char *fname = "xfreerdp-argument.1.xml"; + FILE *fp = NULL; + + /* Open output file for writing, truncate if existing. */ + fp = fopen(fname, "w"); + if( NULL == fp ) + { + fprintf(stderr, "Could not open '%s' for writing.", fname); + return -1; + } + + /* The tag used as header in the manpage */ + fprintf(fp, "\n"); + fprintf(fp, "\tOptions\n"); + fprintf(fp, "\t\t\n"); + + /* Iterate over argument struct and write data to docbook 4.5 + * compatible XML */ + if( elements < 2 ) + { + fprintf(stderr, "The argument array 'args' is empty, writing an empty file."); + elements = 1; + } + + for(x=0; x\n"); + if( COMMAND_LINE_VALUE_REQUIRED == arg->Flags ) + fprintf(fp, "\t\t\t\t %s\n", tr_esc_str(arg->Name), tr_esc_str(arg->Format) ); + else + fprintf(fp, "\t\t\t\t\n", tr_esc_str(arg->Name) ); + fprintf(fp, "\t\t\t\t\n"); + fprintf(fp, "\t\t\t\t\t%s\n", tr_esc_str(arg->Text)); + + fprintf(fp, "\t\t\t\t\n"); + fprintf(fp, "\t\t\t\n"); + } + + fprintf(fp, "\t\t\n"); + fprintf(fp, "\t\n"); + fclose(fp); + + if(NULL != tmp) + free(tmp); + + return 0; +} + diff --git a/client/X11/xfreerdp-channels.1.xml b/client/X11/xfreerdp-channels.1.xml new file mode 100644 index 000000000..e69de29bb diff --git a/client/X11/xfreerdp-examples.1.xml b/client/X11/xfreerdp-examples.1.xml new file mode 100644 index 000000000..462649f68 --- /dev/null +++ b/client/X11/xfreerdp-examples.1.xml @@ -0,0 +1,89 @@ + + Examples + + + xfreerdp connection.rdp /p:Pwd123! /f + + Connect in fullscreen mode using a stored configuration connection.rdp and the password Pwd123! + + + + xfreerdp /u:CONTOSO\\JohnDoe /p:Pwd123! /v:rdp.contoso.com + + Connect to host rdp.contoso.com with user CONTOSO\\JohnDoe and password Pwd123! + + + + xfreerdp /u:JohnDoe /p:Pwd123! /w:1366 /h:768 /v:192.168.1.100:4489 + + Connect to host 192.168.1.100 on port 4489 with user JohnDoe, password Pwd123!. The screen width is set to 1366 and the height to 768 + + + + xfreerdp /u:JohnDoe /p:Pwd123! /vmconnect:C824F53E-95D2-46C6-9A18-23A5BB403532 /v:192.168. 1.100 + + Establish a connection to host 192.168.1.100 with user JohnDoe, password Pwd123! and connect to Hyper-V console (use port 2179, disable negotiation) with VMID C824F53E-95D2-46C6-9A18-23A5BB403532 + + + + +clipboard + + Activate clipboard redirection + + + + /drive:home,/home/user + + Activate drive redirection of /home/user as home drive + + + + /smartcard:<device> + + Activate smartcard redirection for device device + + + + /printer:<device>,<driver> + + Activate printer redirection for printer device using driver driver + + + + /serial:<device> + + Activate serial port redirection for port device + + + + /parallel:<device> + + Activate parallel port redirection for port device + + + + /sound:sys:alsa + + Activate audio output redirection using device sys:alsa + + + + /microphone:sys:alsa + + Activate audio input redirection using device sys:alsa + + + + /multimedia:sys:alsa + + Activate multimedia redirection using device sys:alsa + + + + /usb:id,dev:054c:0268 + + Activate USB device redirection for the device identified by 054c:0268 + + + + diff --git a/client/X11/xfreerdp.1.xml b/client/X11/xfreerdp.1.xml deleted file mode 100644 index bf7f774e6..000000000 --- a/client/X11/xfreerdp.1.xml +++ /dev/null @@ -1,571 +0,0 @@ - - - - 2011-08-27 - - The FreeRDP Team - - - - xfreerdp - 1 - freerdp - xfreerdp - - - xfreerdp - FreeRDP X11 client - - - - 2011-08-27 - - - xfreerdp [options] server[:port] [[options] server[:port] …] - - - - - 2011-08-27 - - DESCRIPTION - - xfreerdp is an X11 Remote Desktop Protocol (RDP) - client which is part of the FreeRDP project. An RDP server is built-in - to many editions of Windows. Alternative servers included xrdp and VRDP (VirtualBox). - - - - OPTIONS - - - -0 - - - Attach to the admin console of the server. - - - - - -a bpp - - - Sets the color depth for the connection to bpp bits per pixel. - Valid values are 8, 15, 16, 24 and 32. The default value is the color depth of the FreeRDP-window. - - - - - -c dir - - - Sets the working-dir to dir. - This parameter is only used when an AlternateShell () is requested. - dir should contain the executable file specified in the AlternateShell. - - - - - -D - - - Removes the windows decorations. - - - - - -d - - - Domain used in authentication. - - - - - -f - - - start in full screen mode. This mode can always be en- and disabled using Ctrl-Alt-Enter. - - - - - -T text - - - Sets the window title to text. - - - - - -g geometry - - - Sets the size of the FreeRDP window (and of the remote desktop, when establishing a new connection). - geometry can have one of the following forms: - - - - WxH - - in this case the resulting window will be of - WxH pixels. - - - - - P% - - in this case the resulting window will be P% - of your screen. - - - - - The special keyword workarea - - in this case the resulting window will be of the same size as your workarea. - - - - - - - - -h - - - Print help. - - - - - -k id - - - Sets the keyboard-layout-id to id. - - - - - -K - - - Do not interfere with window manager bindings. Normally, xfreerdp captures all keystrokes while its window is focused. - - - - - -n hostname - - - Set the reported client hostname to hostname. - Default is to automatically detect the hostname. - - - - - -o - - - Play audio on the console instead of redirecting to the client. - - - - - -p password - - - Password used in authentication. - - - - - -s shell - - - Sets the startup-shell to shell. - This parameter should contain a complete path to the alternate shell. - If the alternete shell requires a different working directory use . - - - - - -t port - - - Connect to port, instead of the default 3389. - - - - - -u username - - - Username used in authentication. - - - - - -x flag - - - Set the experience performance flags. - flag can be one of: - - - - m - (modem): Equivalent to 15. - - - - - b - (broadband): Equivalent to 1. - - - - - l - (lan): Equivalent to 0. - - - - - num - A hexadecimal number that - represents a bit-mask, were numbers mean the following - Taken from - MS-RDPBCGR Section 2.2.1.11.1.1.1 - Extended Info Packet: - - - 1: Disable desktop wallpaper. - - - 2: Disable full-window drag (only the window outline is displayed when the window is moved). - - - 4: Disable menu animations. - - - 8: Disable user interface themes. - - - 20: Disable mouse cursor shadows. - - - 40: Disable cursor blinking. - - - 80: Enable font smoothing. - - - 100: Enable Desktop Composition. - - - - - - - - - - -X xid - - embed xfreerdp into window with xid. - - - - -z - - - Enable compression. - - - - - --app - - - initialize a RemoteApp connection. This implies -g workarea. - - - - - --no-auth - - - Skips authentication. This is useful e.g. for the current FreeRDP server that doesn't yet support server-side authentication. - - - - - --authonly - - - Only authenticates. This is useful to test your credentials (username and password). - Returns status code 0 if the client can connect, 1 otherwise. Requires a username, - password and connection host at the command line. - - - - - --bcv3 codec - - Use codec for bitmap cache v3 - - - - - --no-bmp-cache - - - Disable bitmap cache. - - - - - --certificate-name name - - - use name for the logon certificate, instead of the server name - - - - - --composition - - - Enable composition (RDVH only, not to be confused with remote composition). - - - - - --ext extname - - - load extension extname - - - - - --no-fastpath - - - Disables fast-path. Use slow-path packets instead, which have larger headers. - It might be good for debugging certain issues when you suspect it might be - linked to the parsing of one of the two header types. - - - - - --from-stdin - - Prompts for unspecified arguments -u username, -p - password, -d domain and connection host. This is useful to - hide arguments from ps. Also useful for scripts that will - feed these arguments to the client via (what else?) stdin. - - - - - --disable-full-window-drag - - - Disable full window drag. - - - - - --gdi backend - - - GDI (Graphics Device Interface) rendering backend. backend can be either sw (software) or hw (hardware). - - - - - --ignore-certificate - - - ignore verification of logon certificate. - - - - - --kbd-list - - - list all keyboard layout ids used by -k - - - - - --disable-menu-animations - - - Disable menu animations. - - - - - --no-motion - - - Don't send mouse motion events. - - - - - --no-nego - - disable negotiation of security layer and enforce highest enabled security protocol. - - - - - --no-nla - - - Disable network level authentication. - - - - - --nsc - - - Enable NSCodec. - - - - - --no-osb - - - Disable off screen bitmaps. - - - - - --pcb blob - - - Use preconnection blob. - - - - - --pcid id - - - Use preconnection id. - - - - - --plugin pluginname - - - load pluginname - - - - - --no-rdp - - - Disable Standard RDP encryption. - - - - - --rfx - - - Enable RemoteFX. - - - - - --rfx-mode - - - RemoteFX operational flags. flags can be either v[ideo], i[mage]), default is video. - - - - - --no-salted-checksum - - - disable salted checksums with Standard RDP encryption. - - - - - --ntlm - - - force NTLM protocol version. version can be one of 1 or 2. - - - - - --sec proto - - - force protocol security. proto can be one of rdp, tls or nla. - - - - - --disable-theming - - - Disable theming. - - - - - --no-tls - - - Disable TLS encryption. - - - - - --tsg -username -password -hostname - - - Use Terminal Server Gateway with -username -password -hostname. - - - - - --version - - - Print version information. - - - - - --disable-wallpaper - - - Disable wallpaper. - - - - - - - LINKS - - http://www.freerdp.com/ - - - diff --git a/client/X11/xfreerdp.1.xml.in b/client/X11/xfreerdp.1.xml.in new file mode 100644 index 000000000..4dbb42083 --- /dev/null +++ b/client/X11/xfreerdp.1.xml.in @@ -0,0 +1,60 @@ + + + + + ] +> + + + + @MAN_TODAY@ + + The FreeRDP Team + + + + xfreerdp + 1 + freerdp + xfreerdp + + + xfreerdp + FreeRDP X11 client + + + + @MAN_TODAY@ + + + xfreerdp [file] [options] [/v:server[:port]] + + + + + @MAN_TODAY@ + + DESCRIPTION + + xfreerdp is an X11 Remote Desktop Protocol (RDP) + client which is part of the FreeRDP project. An RDP server is built-in + to many editions of Windows. Alternative servers included xrdp and VRDP (VirtualBox). + + + + &syntax; + + &channels; + + &examples; + + + LINKS + + http://www.freerdp.com/ + + + diff --git a/client/common/CMakeLists.txt b/client/common/CMakeLists.txt index e249cd0db..0179a53a1 100644 --- a/client/common/CMakeLists.txt +++ b/client/common/CMakeLists.txt @@ -25,9 +25,10 @@ set(${MODULE_PREFIX}_SRCS compatibility.h file.c) -set(FREERDP_CHANNELS_CLIENT_PATH "../../channels/client") foreach(FREERDP_CHANNELS_CLIENT_SRC ${FREERDP_CHANNELS_CLIENT_SRCS}) - set(${MODULE_PREFIX}_SRCS ${${MODULE_PREFIX}_SRCS} "${FREERDP_CHANNELS_CLIENT_PATH}/${FREERDP_CHANNELS_CLIENT_SRC}") + get_filename_component(NINC ${FREERDP_CHANNELS_CLIENT_SRC} PATH) + include_directories(${NINC}) + set(${MODULE_PREFIX}_SRCS ${${MODULE_PREFIX}_SRCS} "${FREERDP_CHANNELS_CLIENT_SRC}") endforeach() if(MSVC) diff --git a/cmake/AndroidToolchain.cmake b/cmake/AndroidToolchain.cmake index 9216bf55d..9eeb7beaf 100644 --- a/cmake/AndroidToolchain.cmake +++ b/cmake/AndroidToolchain.cmake @@ -1,5 +1,5 @@ # Copyright (c) 2010-2011, Ethan Rublee -# Copyright (c) 2011-2012, Andrey Kamaev +# Copyright (c) 2011-2013, Andrey Kamaev # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -35,7 +35,6 @@ # # The file is mantained by the OpenCV project. The latest version can be get at # http://code.opencv.org/projects/opencv/repository/revisions/master/changes/android/android.toolchain.cmake -# Git commit: 084b1c796900b0825fc4e0593ab3143da3f3a90e # # Usage Linux: # $ export ANDROID_NDK=/absolute/path/to/the/android-ndk @@ -282,8 +281,19 @@ # [+] updated for NDK r8c # [+] added support for clang compiler # - December 2012 +# [+] suppress warning about unused CMAKE_TOOLCHAIN_FILE variable +# [+] adjust API level to closest compatible as NDK does # [~] fixed ccache full path search # [+] updated for NDK r8d +# [~] compiler options are aligned with NDK r8d +# - March 2013 +# [+] updated for NDK r8e (x86 version) +# [+] support x86_64 version of NDK +# - April 2013 +# [+] support non-release NDK layouts (from Linaro git and Android git) +# [~] automatically detect if explicit link to crtbegin_*.o is needed +# - June 2013 +# [~] fixed stl include path for standalone toolchain made by NDK >= r8c # ------------------------------------------------------------------------------ cmake_minimum_required( VERSION 2.6.3 ) @@ -293,6 +303,10 @@ if( DEFINED CMAKE_CROSSCOMPILING ) return() endif() +if( CMAKE_TOOLCHAIN_FILE ) + # touch toolchain variable only to suppress "unused variable" warning +endif() + get_property( _CMAKE_IN_TRY_COMPILE GLOBAL PROPERTY IN_TRY_COMPILE ) if( _CMAKE_IN_TRY_COMPILE ) include( "${CMAKE_CURRENT_SOURCE_DIR}/../android.toolchain.config.cmake" OPTIONAL ) @@ -312,7 +326,7 @@ endif() # rpath makes low sence for Android set( CMAKE_SKIP_RPATH TRUE CACHE BOOL "If set, runtime paths are not added when using shared libraries." ) -set( ANDROID_SUPPORTED_NDK_VERSIONS ${ANDROID_EXTRA_NDK_VERSIONS} -r8e -r8d -r8c -r8b -r8 -r7c -r7b -r7 -r6b -r6 -r5c -r5b -r5 "" ) +set( ANDROID_SUPPORTED_NDK_VERSIONS ${ANDROID_EXTRA_NDK_VERSIONS} -r9 -r8e -r8d -r8c -r8b -r8 -r7c -r7b -r7 -r6b -r6 -r5c -r5b -r5 "" ) if(NOT DEFINED ANDROID_NDK_SEARCH_PATHS) if( CMAKE_HOST_WIN32 ) file( TO_CMAKE_PATH "$ENV{PROGRAMFILES}" ANDROID_NDK_SEARCH_PATHS ) @@ -456,19 +470,32 @@ if( ANDROID_FORBID_SYGWIN ) endif() endif() + # detect current host platform +if( NOT DEFINED ANDROID_NDK_HOST_X64 AND CMAKE_HOST_SYSTEM_PROCESSOR MATCHES "amd64|x86_64|AMD64") + set( ANDROID_NDK_HOST_X64 1 CACHE BOOL "Try to use 64-bit compiler toolchain" ) + mark_as_advanced( ANDROID_NDK_HOST_X64 ) +endif() + set( TOOL_OS_SUFFIX "" ) if( CMAKE_HOST_APPLE ) - set( ANDROID_NDK_HOST_SYSTEM_NAME "darwin-x86" ) + set( ANDROID_NDK_HOST_SYSTEM_NAME "darwin-x86_64" ) + set( ANDROID_NDK_HOST_SYSTEM_NAME2 "darwin-x86" ) elseif( CMAKE_HOST_WIN32 ) - set( ANDROID_NDK_HOST_SYSTEM_NAME "windows" ) + set( ANDROID_NDK_HOST_SYSTEM_NAME "windows-x86_64" ) + set( ANDROID_NDK_HOST_SYSTEM_NAME2 "windows" ) set( TOOL_OS_SUFFIX ".exe" ) elseif( CMAKE_HOST_UNIX ) - set( ANDROID_NDK_HOST_SYSTEM_NAME "linux-x86" ) + set( ANDROID_NDK_HOST_SYSTEM_NAME "linux-x86_64" ) + set( ANDROID_NDK_HOST_SYSTEM_NAME2 "linux-x86" ) else() message( FATAL_ERROR "Cross-compilation on your platform is not supported by this cmake toolchain" ) endif() +if( NOT ANDROID_NDK_HOST_X64 ) + set( ANDROID_NDK_HOST_SYSTEM_NAME ${ANDROID_NDK_HOST_SYSTEM_NAME2} ) +endif() + # see if we have path to Android NDK __INIT_VARIABLE( ANDROID_NDK PATH ENV_ANDROID_NDK ) if( NOT ANDROID_NDK ) @@ -500,35 +527,19 @@ if( NOT ANDROID_NDK ) endif( ANDROID_NDK ) endif( NOT ANDROID_STANDALONE_TOOLCHAIN ) endif( NOT ANDROID_NDK ) + # remember found paths if( ANDROID_NDK ) get_filename_component( ANDROID_NDK "${ANDROID_NDK}" ABSOLUTE ) - # try to detect change - if( CMAKE_AR ) - string( LENGTH "${ANDROID_NDK}" __length ) - string( SUBSTRING "${CMAKE_AR}" 0 ${__length} __androidNdkPreviousPath ) - if( NOT __androidNdkPreviousPath STREQUAL ANDROID_NDK ) - message( FATAL_ERROR "It is not possible to change the path to the NDK on subsequent CMake run. You must remove all generated files from your build folder first. - " ) - endif() - unset( __androidNdkPreviousPath ) - unset( __length ) - endif() set( ANDROID_NDK "${ANDROID_NDK}" CACHE INTERNAL "Path of the Android NDK" FORCE ) set( BUILD_WITH_ANDROID_NDK True ) - file( STRINGS "${ANDROID_NDK}/RELEASE.TXT" ANDROID_NDK_RELEASE_TXT LIMIT_COUNT 1 REGEX r[0-9]+[a-z]? ) - - if(${ANDROID_NDK_RELEASE_TXT} MATCHES "^r[0-9]+[a-z] \([^ ]+\)$") - string( REGEX REPLACE "^(r[0-9]+[a-z]) \(([^ ]+)\)$" "\\1" ANDROID_NDK_RELEASE "${ANDROID_NDK_RELEASE_TXT}" ) - string( REGEX REPLACE "^(r[0-9]+[a-z]) \(([^ ]+)\)$" "\\2" ANDROID_NDK_RELEASE_EXTRA "${ANDROID_NDK_RELEASE_TXT}" ) - - set( ANDROID_NDK_64BIT True) - set( ANDROID_NDK_HOST_SYSTEM_NAME "${ANDROID_NDK_HOST_SYSTEM_NAME}_64" ) - + if( EXISTS "${ANDROID_NDK}/RELEASE.TXT" ) + file( STRINGS "${ANDROID_NDK}/RELEASE.TXT" ANDROID_NDK_RELEASE_FULL LIMIT_COUNT 1 REGEX r[0-9]+[a-z]? ) + string( REGEX MATCH r[0-9]+[a-z]? ANDROID_NDK_RELEASE "${ANDROID_NDK_RELEASE_FULL}" ) else() - set( ANDROID_NDK_RELEASE "${ANDROID_NDK_RELEASE_TXT}" ) + set( ANDROID_NDK_RELEASE "r1x" ) + set( ANDROID_NDK_RELEASE_FULL "unreleased" ) endif() - elseif( ANDROID_STANDALONE_TOOLCHAIN ) get_filename_component( ANDROID_STANDALONE_TOOLCHAIN "${ANDROID_STANDALONE_TOOLCHAIN}" ABSOLUTE ) # try to detect change @@ -555,6 +566,51 @@ else() sudo ln -s ~/my-android-toolchain ${ANDROID_STANDALONE_TOOLCHAIN_SEARCH_PATH}" ) endif() +# android NDK layout +if( BUILD_WITH_ANDROID_NDK ) + if( NOT DEFINED ANDROID_NDK_LAYOUT ) + # try to automatically detect the layout + if( EXISTS "${ANDROID_NDK}/RELEASE.TXT") + set( ANDROID_NDK_LAYOUT "RELEASE" ) + elseif( EXISTS "${ANDROID_NDK}/../../linux-x86/toolchain/" ) + set( ANDROID_NDK_LAYOUT "LINARO" ) + elseif( EXISTS "${ANDROID_NDK}/../../gcc/" ) + set( ANDROID_NDK_LAYOUT "ANDROID" ) + endif() + endif() + set( ANDROID_NDK_LAYOUT "${ANDROID_NDK_LAYOUT}" CACHE STRING "The inner layout of NDK" ) + mark_as_advanced( ANDROID_NDK_LAYOUT ) + if( ANDROID_NDK_LAYOUT STREQUAL "LINARO" ) + set( ANDROID_NDK_HOST_SYSTEM_NAME ${ANDROID_NDK_HOST_SYSTEM_NAME2} ) # only 32-bit at the moment + set( ANDROID_NDK_TOOLCHAINS_PATH "${ANDROID_NDK}/../../${ANDROID_NDK_HOST_SYSTEM_NAME}/toolchain" ) + set( ANDROID_NDK_TOOLCHAINS_SUBPATH "" ) + set( ANDROID_NDK_TOOLCHAINS_SUBPATH2 "" ) + elseif( ANDROID_NDK_LAYOUT STREQUAL "ANDROID" ) + set( ANDROID_NDK_HOST_SYSTEM_NAME ${ANDROID_NDK_HOST_SYSTEM_NAME2} ) # only 32-bit at the moment + set( ANDROID_NDK_TOOLCHAINS_PATH "${ANDROID_NDK}/../../gcc/${ANDROID_NDK_HOST_SYSTEM_NAME}/arm" ) + set( ANDROID_NDK_TOOLCHAINS_SUBPATH "" ) + set( ANDROID_NDK_TOOLCHAINS_SUBPATH2 "" ) + else() # ANDROID_NDK_LAYOUT STREQUAL "RELEASE" + set( ANDROID_NDK_TOOLCHAINS_PATH "${ANDROID_NDK}/toolchains" ) + set( ANDROID_NDK_TOOLCHAINS_SUBPATH "/prebuilt/${ANDROID_NDK_HOST_SYSTEM_NAME}" ) + set( ANDROID_NDK_TOOLCHAINS_SUBPATH2 "/prebuilt/${ANDROID_NDK_HOST_SYSTEM_NAME2}" ) + endif() + get_filename_component( ANDROID_NDK_TOOLCHAINS_PATH "${ANDROID_NDK_TOOLCHAINS_PATH}" ABSOLUTE ) + + # try to detect change of NDK + if( CMAKE_AR ) + string( LENGTH "${ANDROID_NDK_TOOLCHAINS_PATH}" __length ) + string( SUBSTRING "${CMAKE_AR}" 0 ${__length} __androidNdkPreviousPath ) + if( NOT __androidNdkPreviousPath STREQUAL ANDROID_NDK_TOOLCHAINS_PATH ) + message( FATAL_ERROR "It is not possible to change the path to the NDK on subsequent CMake run. You must remove all generated files from your build folder first. + " ) + endif() + unset( __androidNdkPreviousPath ) + unset( __length ) + endif() +endif() + + # get all the details about standalone toolchain if( BUILD_WITH_STANDALONE_TOOLCHAIN ) __DETECT_NATIVE_API_LEVEL( ANDROID_SUPPORTED_NATIVE_API_LEVELS "${ANDROID_STANDALONE_TOOLCHAIN}/sysroot/usr/include/android/api-level.h" ) @@ -582,22 +638,27 @@ if( BUILD_WITH_STANDALONE_TOOLCHAIN ) endif() endif() -macro( __GLOB_NDK_TOOLCHAINS __availableToolchainsVar ) - foreach( __toolchain ${${__availableToolchainsVar}} ) - if( "${__toolchain}" MATCHES "-clang3[.][0-9]$" AND NOT EXISTS "${ANDROID_NDK}/toolchains/${__toolchain}/prebuilt/" ) +macro( __GLOB_NDK_TOOLCHAINS __availableToolchainsVar __availableToolchainsLst __toolchain_subpath ) + foreach( __toolchain ${${__availableToolchainsLst}} ) + if( "${__toolchain}" MATCHES "-clang3[.][0-9]$" AND NOT EXISTS "${ANDROID_NDK_TOOLCHAINS_PATH}/${__toolchain}${__toolchain_subpath}" ) string( REGEX REPLACE "-clang3[.][0-9]$" "-4.6" __gcc_toolchain "${__toolchain}" ) else() set( __gcc_toolchain "${__toolchain}" ) endif() - __DETECT_TOOLCHAIN_MACHINE_NAME( __machine "${ANDROID_NDK}/toolchains/${__gcc_toolchain}/prebuilt/${ANDROID_NDK_HOST_SYSTEM_NAME}" ) + __DETECT_TOOLCHAIN_MACHINE_NAME( __machine "${ANDROID_NDK_TOOLCHAINS_PATH}/${__gcc_toolchain}${__toolchain_subpath}" ) if( __machine ) - string( REGEX MATCH "[0-9]+[.][0-9]+([.][0-9]+)?$" __version "${__gcc_toolchain}" ) - string( REGEX MATCH "^[^-]+" __arch "${__gcc_toolchain}" ) + string( REGEX MATCH "[0-9]+[.][0-9]+([.][0-9x]+)?$" __version "${__gcc_toolchain}" ) + if( __machine MATCHES i686 ) + set( __arch "x86" ) + elseif( __machine MATCHES arm ) + set( __arch "arm" ) + elseif( __machine MATCHES mipsel ) + set( __arch "mipsel" ) + endif() list( APPEND __availableToolchainMachines "${__machine}" ) list( APPEND __availableToolchainArchs "${__arch}" ) list( APPEND __availableToolchainCompilerVersions "${__version}" ) - else() - list( REMOVE_ITEM ${__availableToolchainsVar} "${__toolchain}" ) + list( APPEND ${__availableToolchainsVar} "${__toolchain}" ) endif() unset( __gcc_toolchain ) endforeach() @@ -611,19 +672,31 @@ if( BUILD_WITH_ANDROID_NDK ) set( __availableToolchainMachines "" ) set( __availableToolchainArchs "" ) set( __availableToolchainCompilerVersions "" ) - if( ANDROID_TOOLCHAIN_NAME AND EXISTS "${ANDROID_NDK}/toolchains/${ANDROID_TOOLCHAIN_NAME}/" ) + if( ANDROID_TOOLCHAIN_NAME AND EXISTS "${ANDROID_NDK_TOOLCHAINS_PATH}/${ANDROID_TOOLCHAIN_NAME}/" ) # do not go through all toolchains if we know the name - set( __availableToolchains "${ANDROID_TOOLCHAIN_NAME}" ) - __GLOB_NDK_TOOLCHAINS( __availableToolchains ) + set( __availableToolchainsLst "${ANDROID_TOOLCHAIN_NAME}" ) + __GLOB_NDK_TOOLCHAINS( __availableToolchains __availableToolchainsLst "${ANDROID_NDK_TOOLCHAINS_SUBPATH}" ) + if( NOT __availableToolchains AND NOT ANDROID_NDK_TOOLCHAINS_SUBPATH STREQUAL ANDROID_NDK_TOOLCHAINS_SUBPATH2 ) + __GLOB_NDK_TOOLCHAINS( __availableToolchains __availableToolchainsLst "${ANDROID_NDK_TOOLCHAINS_SUBPATH2}" ) + if( __availableToolchains ) + set( ANDROID_NDK_TOOLCHAINS_SUBPATH ${ANDROID_NDK_TOOLCHAINS_SUBPATH2} ) + endif() + endif() endif() if( NOT __availableToolchains ) - file( GLOB __availableToolchains RELATIVE "${ANDROID_NDK}/toolchains" "${ANDROID_NDK}/toolchains/*" ) + file( GLOB __availableToolchainsLst RELATIVE "${ANDROID_NDK_TOOLCHAINS_PATH}" "${ANDROID_NDK_TOOLCHAINS_PATH}/*" ) if( __availableToolchains ) - list(SORT __availableToolchains) # we need clang to go after gcc + list(SORT __availableToolchainsLst) # we need clang to go after gcc + endif() + __LIST_FILTER( __availableToolchainsLst "^[.]" ) + __LIST_FILTER( __availableToolchainsLst "llvm" ) + __GLOB_NDK_TOOLCHAINS( __availableToolchains __availableToolchainsLst "${ANDROID_NDK_TOOLCHAINS_SUBPATH}" ) + if( NOT __availableToolchains AND NOT ANDROID_NDK_TOOLCHAINS_SUBPATH STREQUAL ANDROID_NDK_TOOLCHAINS_SUBPATH2 ) + __GLOB_NDK_TOOLCHAINS( __availableToolchains __availableToolchainsLst "${ANDROID_NDK_TOOLCHAINS_SUBPATH2}" ) + if( __availableToolchains ) + set( ANDROID_NDK_TOOLCHAINS_SUBPATH ${ANDROID_NDK_TOOLCHAINS_SUBPATH2} ) + endif() endif() - __LIST_FILTER( __availableToolchains "^[.]" ) - __LIST_FILTER( __availableToolchains "llvm" ) - __GLOB_NDK_TOOLCHAINS( __availableToolchains ) endif() if( NOT __availableToolchains ) message( FATAL_ERROR "Could not find any working toolchain in the NDK. Probably your Android NDK is broken." ) @@ -636,11 +709,11 @@ set( __uniqToolchainArchNames ${__availableToolchainArchs} ) list( REMOVE_DUPLICATES __uniqToolchainArchNames ) list( SORT __uniqToolchainArchNames ) foreach( __arch ${__uniqToolchainArchNames} ) -list( APPEND ANDROID_SUPPORTED_ABIS ${ANDROID_SUPPORTED_ABIS_${__arch}} ) + list( APPEND ANDROID_SUPPORTED_ABIS ${ANDROID_SUPPORTED_ABIS_${__arch}} ) endforeach() unset( __uniqToolchainArchNames ) if( NOT ANDROID_SUPPORTED_ABIS ) -message( FATAL_ERROR "No one of known Android ABIs is supported by this cmake toolchain." ) + message( FATAL_ERROR "No one of known Android ABIs is supported by this cmake toolchain." ) endif() # choose target ABI @@ -752,6 +825,7 @@ else() list( GET __availableToolchainArchs ${__idx} __toolchainArch ) if( __toolchainArch STREQUAL ANDROID_ARCH_FULLNAME ) list( GET __availableToolchainCompilerVersions ${__idx} __toolchainVersion ) + string( REPLACE "x" "99" __toolchainVersion "${__toolchainVersion}") if( __toolchainVersion VERSION_GREATER __toolchainMaxVersion ) set( __toolchainMaxVersion "${__toolchainVersion}" ) set( __toolchainIdx ${__idx} ) @@ -779,11 +853,22 @@ unset( __availableToolchainCompilerVersions ) # choose native API level __INIT_VARIABLE( ANDROID_NATIVE_API_LEVEL ENV_ANDROID_NATIVE_API_LEVEL ANDROID_API_LEVEL ENV_ANDROID_API_LEVEL ANDROID_STANDALONE_TOOLCHAIN_API_LEVEL ANDROID_DEFAULT_NDK_API_LEVEL_${ANDROID_ARCH_NAME} ANDROID_DEFAULT_NDK_API_LEVEL ) string( REGEX MATCH "[0-9]+" ANDROID_NATIVE_API_LEVEL "${ANDROID_NATIVE_API_LEVEL}" ) -# TODO: filter out unsupported levels +# adjust API level +set( __real_api_level ${ANDROID_DEFAULT_NDK_API_LEVEL_${ANDROID_ARCH_NAME}} ) +foreach( __level ${ANDROID_SUPPORTED_NATIVE_API_LEVELS} ) + if( NOT __level GREATER ANDROID_NATIVE_API_LEVEL AND NOT __level LESS __real_api_level ) + set( __real_api_level ${__level} ) + endif() +endforeach() +if( __real_api_level AND NOT ANDROID_NATIVE_API_LEVEL EQUAL __real_api_level ) + message( STATUS "Adjusting Android API level 'android-${ANDROID_NATIVE_API_LEVEL}' to 'android-${__real_api_level}'") + set( ANDROID_NATIVE_API_LEVEL ${__real_api_level} ) +endif() +unset(__real_api_level) # validate list( FIND ANDROID_SUPPORTED_NATIVE_API_LEVELS "${ANDROID_NATIVE_API_LEVEL}" __levelIdx ) if( __levelIdx EQUAL -1 ) - message( SEND_ERROR "Specified Android native API level (${ANDROID_NATIVE_API_LEVEL}) is not supported by your NDK/toolchain." ) + message( SEND_ERROR "Specified Android native API level 'android-${ANDROID_NATIVE_API_LEVEL}' is not supported by your NDK/toolchain." ) else() if( BUILD_WITH_ANDROID_NDK ) __DETECT_NATIVE_API_LEVEL( __realApiLevel "${ANDROID_NDK}/platforms/android-${ANDROID_NATIVE_API_LEVEL}/arch-${ANDROID_ARCH_NAME}/usr/include/android/api-level.h" ) @@ -893,7 +978,11 @@ if( BUILD_WITH_STANDALONE_TOOLCHAIN ) set( ANDROID_SYSROOT "${ANDROID_STANDALONE_TOOLCHAIN}/sysroot" ) if( NOT ANDROID_STL STREQUAL "none" ) - set( ANDROID_STL_INCLUDE_DIRS "${ANDROID_STANDALONE_TOOLCHAIN}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/include/c++/${ANDROID_COMPILER_VERSION}" ) + set( ANDROID_STL_INCLUDE_DIRS "${ANDROID_STANDALONE_TOOLCHAIN}/include/c++/${ANDROID_COMPILER_VERSION}" ) + if( NOT EXISTS "${ANDROID_STL_INCLUDE_DIRS}" ) + # old location ( pre r8c ) + set( ANDROID_STL_INCLUDE_DIRS "${ANDROID_STANDALONE_TOOLCHAIN}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/include/c++/${ANDROID_COMPILER_VERSION}" ) + endif() if( ARMEABI_V7A AND EXISTS "${ANDROID_STL_INCLUDE_DIRS}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/${CMAKE_SYSTEM_PROCESSOR}/bits" ) list( APPEND ANDROID_STL_INCLUDE_DIRS "${ANDROID_STL_INCLUDE_DIRS}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/${CMAKE_SYSTEM_PROCESSOR}" ) elseif( ARMEABI AND NOT ANDROID_FORCE_ARM_BUILD AND EXISTS "${ANDROID_STL_INCLUDE_DIRS}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/thumb/bits" ) @@ -944,11 +1033,11 @@ if( "${ANDROID_TOOLCHAIN_NAME}" STREQUAL "standalone-clang" ) elseif( "${ANDROID_TOOLCHAIN_NAME}" MATCHES "-clang3[.][0-9]?$" ) string( REGEX MATCH "3[.][0-9]$" ANDROID_CLANG_VERSION "${ANDROID_TOOLCHAIN_NAME}") string( REGEX REPLACE "-clang${ANDROID_CLANG_VERSION}$" "-4.6" ANDROID_GCC_TOOLCHAIN_NAME "${ANDROID_TOOLCHAIN_NAME}" ) - if( NOT EXISTS "${ANDROID_NDK}/toolchains/llvm-${ANDROID_CLANG_VERSION}/prebuilt/${ANDROID_NDK_HOST_SYSTEM_NAME}/bin/clang${TOOL_OS_SUFFIX}" ) - message( FATAL_ERROR "Could not find the " ) + if( NOT EXISTS "${ANDROID_NDK_TOOLCHAINS_PATH}/llvm-${ANDROID_CLANG_VERSION}${ANDROID_NDK_TOOLCHAINS_SUBPATH}/bin/clang${TOOL_OS_SUFFIX}" ) + message( FATAL_ERROR "Could not find the Clang compiler driver" ) endif() set( ANDROID_COMPILER_IS_CLANG 1 ) - set( ANDROID_CLANG_TOOLCHAIN_ROOT "${ANDROID_NDK}/toolchains/llvm-${ANDROID_CLANG_VERSION}/prebuilt/${ANDROID_NDK_HOST_SYSTEM_NAME}" ) + set( ANDROID_CLANG_TOOLCHAIN_ROOT "${ANDROID_NDK_TOOLCHAINS_PATH}/llvm-${ANDROID_CLANG_VERSION}${ANDROID_NDK_TOOLCHAINS_SUBPATH}" ) else() set( ANDROID_GCC_TOOLCHAIN_NAME "${ANDROID_TOOLCHAIN_NAME}" ) unset( ANDROID_COMPILER_IS_CLANG CACHE ) @@ -962,7 +1051,7 @@ endif() # setup paths and STL for NDK if( BUILD_WITH_ANDROID_NDK ) - set( ANDROID_TOOLCHAIN_ROOT "${ANDROID_NDK}/toolchains/${ANDROID_GCC_TOOLCHAIN_NAME}/prebuilt/${ANDROID_NDK_HOST_SYSTEM_NAME}" ) + set( ANDROID_TOOLCHAIN_ROOT "${ANDROID_NDK_TOOLCHAINS_PATH}/${ANDROID_GCC_TOOLCHAIN_NAME}${ANDROID_NDK_TOOLCHAINS_SUBPATH}" ) set( ANDROID_SYSROOT "${ANDROID_NDK}/platforms/android-${ANDROID_NATIVE_API_LEVEL}/arch-${ANDROID_ARCH_NAME}" ) if( ANDROID_STL STREQUAL "none" ) @@ -1021,11 +1110,11 @@ if( BUILD_WITH_ANDROID_NDK ) endif() # find libsupc++.a - rtti & exceptions if( ANDROID_STL STREQUAL "system_re" OR ANDROID_STL MATCHES "gnustl" ) - if( ANDROID_NDK_RELEASE STRGREATER "r8" ) # r8b - set( __libsupcxx "${ANDROID_NDK}/sources/cxx-stl/gnu-libstdc++/${ANDROID_COMPILER_VERSION}/libs/${ANDROID_NDK_ABI_NAME}/libsupc++.a" ) - elseif( NOT ANDROID_NDK_RELEASE STRLESS "r7" AND ANDROID_NDK_RELEASE STRLESS "r8b") - set( __libsupcxx "${ANDROID_NDK}/sources/cxx-stl/gnu-libstdc++/libs/${ANDROID_NDK_ABI_NAME}/libsupc++.a" ) - else( ANDROID_NDK_RELEASE STRLESS "r7" ) + set( __libsupcxx "${ANDROID_NDK}/sources/cxx-stl/gnu-libstdc++/${ANDROID_COMPILER_VERSION}/libs/${ANDROID_NDK_ABI_NAME}/libsupc++.a" ) # r8b or newer + if( NOT EXISTS "${__libsupcxx}" ) + set( __libsupcxx "${ANDROID_NDK}/sources/cxx-stl/gnu-libstdc++/libs/${ANDROID_NDK_ABI_NAME}/libsupc++.a" ) # r7-r8 + endif() + if( NOT EXISTS "${__libsupcxx}" ) # before r7 if( ARMEABI_V7A ) if( ANDROID_FORCE_ARM_BUILD ) set( __libsupcxx "${ANDROID_TOOLCHAIN_ROOT}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/lib/${CMAKE_SYSTEM_PROCESSOR}/libsupc++.a" ) @@ -1075,7 +1164,7 @@ unset( _ndk_ccache ) # setup the cross-compiler if( NOT CMAKE_C_COMPILER ) - if( NDK_CCACHE ) + if( NDK_CCACHE AND NOT ANDROID_SYSROOT MATCHES "[ ;\"]" ) set( CMAKE_C_COMPILER "${NDK_CCACHE}" CACHE PATH "ccache as C compiler" ) set( CMAKE_CXX_COMPILER "${NDK_CCACHE}" CACHE PATH "ccache as C++ compiler" ) if( ANDROID_COMPILER_IS_CLANG ) @@ -1147,11 +1236,25 @@ set( CMAKE_ASM_SOURCE_FILE_EXTENSIONS s S asm ) remove_definitions( -DANDROID ) add_definitions( -DANDROID ) -if(ANDROID_SYSROOT MATCHES "[ ;\"]") - set( ANDROID_CXX_FLAGS "--sysroot=\"${ANDROID_SYSROOT}\"" ) +if( ANDROID_SYSROOT MATCHES "[ ;\"]" ) + if( CMAKE_HOST_WIN32 ) + # try to convert path to 8.3 form + file( WRITE "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/cvt83.cmd" "@echo %~s1" ) + execute_process( COMMAND "$ENV{ComSpec}" /c "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/cvt83.cmd" "${ANDROID_SYSROOT}" + OUTPUT_VARIABLE __path OUTPUT_STRIP_TRAILING_WHITESPACE + RESULT_VARIABLE __result ERROR_QUIET ) + if( __result EQUAL 0 ) + file( TO_CMAKE_PATH "${__path}" ANDROID_SYSROOT ) + set( ANDROID_CXX_FLAGS "--sysroot=${ANDROID_SYSROOT}" ) + else() + set( ANDROID_CXX_FLAGS "--sysroot=\"${ANDROID_SYSROOT}\"" ) + endif() + else() + set( ANDROID_CXX_FLAGS "'--sysroot=${ANDROID_SYSROOT}'" ) + endif() if( NOT _CMAKE_IN_TRY_COMPILE ) - # quotes will break try_compile and compiler identification - message(WARNING "Your Android system root has non-alphanumeric symbols. It can break compiler features detection and the whole build.") + # quotes can break try_compile and compiler identification + message(WARNING "Path to your Android NDK (or toolchain) has non-alphanumeric symbols.\nThe build might be broken.\n") endif() else() set( ANDROID_CXX_FLAGS "--sysroot=${ANDROID_SYSROOT}" ) @@ -1159,38 +1262,52 @@ endif() # NDK flags if( ARMEABI OR ARMEABI_V7A ) - set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -fpic -D__ARM_ARCH_5__ -D__ARM_ARCH_5T__ -D__ARM_ARCH_5E__ -D__ARM_ARCH_5TE__" ) + set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -fpic -funwind-tables" ) if( NOT ANDROID_FORCE_ARM_BUILD AND NOT ARMEABI_V6 ) - # It is recommended to use the -mthumb compiler flag to force the generation - # of 16-bit Thumb-1 instructions (the default being 32-bit ARM ones). - set( ANDROID_CXX_FLAGS_RELEASE "-mthumb" ) - set( ANDROID_CXX_FLAGS_DEBUG "-marm -finline-limit=64" ) + set( ANDROID_CXX_FLAGS_RELEASE "-mthumb -fomit-frame-pointer -fno-strict-aliasing" ) + set( ANDROID_CXX_FLAGS_DEBUG "-marm -fno-omit-frame-pointer -fno-strict-aliasing" ) + if( NOT ANDROID_COMPILER_IS_CLANG ) + set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -finline-limit=64" ) + endif() else() # always compile ARMEABI_V6 in arm mode; otherwise there is no difference from ARMEABI - # O3 instead of O2/Os in release mode - like cmake sets for desktop gcc - set( ANDROID_CXX_FLAGS_RELEASE "-marm" ) - set( ANDROID_CXX_FLAGS_DEBUG "-marm -finline-limit=300" ) + set( ANDROID_CXX_FLAGS_RELEASE "-marm -fomit-frame-pointer -fstrict-aliasing" ) + set( ANDROID_CXX_FLAGS_DEBUG "-marm -fno-omit-frame-pointer -fno-strict-aliasing" ) + if( NOT ANDROID_COMPILER_IS_CLANG ) + set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -funswitch-loops -finline-limit=300" ) + endif() endif() elseif( X86 ) - set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -funwind-tables" ) - set( ANDROID_CXX_FLAGS_RELEASE "" ) - set( ANDROID_CXX_FLAGS_DEBUG "-finline-limit=300" ) + set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -funwind-tables" ) + if( NOT ANDROID_COMPILER_IS_CLANG ) + set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -funswitch-loops -finline-limit=300" ) + else() + set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -fPIC" ) + endif() + set( ANDROID_CXX_FLAGS_RELEASE "-fomit-frame-pointer -fstrict-aliasing" ) + set( ANDROID_CXX_FLAGS_DEBUG "-fno-omit-frame-pointer -fno-strict-aliasing" ) elseif( MIPS ) - set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -fpic -funwind-tables -fmessage-length=0 -fno-inline-functions-called-once -frename-registers" ) - set( ANDROID_CXX_FLAGS_RELEASE "-finline-limit=300 -fno-strict-aliasing" ) - set( ANDROID_CXX_FLAGS_DEBUG "-finline-functions -fgcse-after-reload -frerun-cse-after-loop" ) + set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -fpic -fno-strict-aliasing -finline-functions -ffunction-sections -funwind-tables -fmessage-length=0" ) + set( ANDROID_CXX_FLAGS_RELEASE "-fomit-frame-pointer" ) + set( ANDROID_CXX_FLAGS_DEBUG "-fno-omit-frame-pointer" ) + if( NOT ANDROID_COMPILER_IS_CLANG ) + set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -fno-inline-functions-called-once -fgcse-after-reload -frerun-cse-after-loop -frename-registers" ) + set( ANDROID_CXX_FLAGS_RELEASE "${ANDROID_CXX_FLAGS_RELEASE} -funswitch-loops -finline-limit=300" ) + endif() elseif() set( ANDROID_CXX_FLAGS_RELEASE "" ) set( ANDROID_CXX_FLAGS_DEBUG "" ) endif() -if( NOT X86 ) - set( ANDROID_CXX_FLAGS "-Wno-psabi ${ANDROID_CXX_FLAGS}" ) +set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -fsigned-char" ) # good/necessary when porting desktop libraries + +if( NOT X86 AND NOT ANDROID_COMPILER_IS_CLANG ) + set( ANDROID_CXX_FLAGS "-Wno-psabi ${ANDROID_CXX_FLAGS}" ) endif() -set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -fsigned-char" ) # good/necessary when porting desktop libraries -set( ANDROID_CXX_FLAGS_RELEASE "${ANDROID_CXX_FLAGS_RELEASE} -fomit-frame-pointer" ) -set( ANDROID_CXX_FLAGS_DEBUG "${ANDROID_CXX_FLAGS_DEBUG} -fno-strict-aliasing -fno-omit-frame-pointer" ) +if( NOT ANDROID_COMPILER_VERSION VERSION_LESS "4.6" ) + set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -no-canonical-prefixes" ) # see https://android-review.googlesource.com/#/c/47564/ +endif() # ABI-specific flags if( ARMEABI_V7A ) @@ -1208,22 +1325,18 @@ elseif( ARMEABI ) set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -march=armv5te -mtune=xscale -msoft-float" ) endif() +if( ANDROID_STL MATCHES "gnustl" AND (EXISTS "${__libstl}" OR EXISTS "${__libsupcxx}") ) + set( CMAKE_CXX_CREATE_SHARED_LIBRARY " -o " ) + set( CMAKE_CXX_CREATE_SHARED_MODULE " -o " ) + set( CMAKE_CXX_LINK_EXECUTABLE " -o " ) +else() + set( CMAKE_CXX_CREATE_SHARED_LIBRARY " -o " ) + set( CMAKE_CXX_CREATE_SHARED_MODULE " -o " ) + set( CMAKE_CXX_LINK_EXECUTABLE " -o " ) +endif() + # STL if( EXISTS "${__libstl}" OR EXISTS "${__libsupcxx}" ) - if( ANDROID_STL MATCHES "gnustl" ) - set( CMAKE_CXX_CREATE_SHARED_LIBRARY " -o " ) - set( CMAKE_CXX_CREATE_SHARED_MODULE " -o " ) - set( CMAKE_CXX_LINK_EXECUTABLE " -o " ) - else() - set( CMAKE_CXX_CREATE_SHARED_LIBRARY " -o " ) - set( CMAKE_CXX_CREATE_SHARED_MODULE " -o " ) - set( CMAKE_CXX_LINK_EXECUTABLE " -o " ) - endif() - if ( X86 AND ANDROID_STL MATCHES "gnustl" AND ANDROID_NDK_RELEASE STREQUAL "r6" ) - # workaround "undefined reference to `__dso_handle'" problem - set( CMAKE_CXX_CREATE_SHARED_LIBRARY "${CMAKE_CXX_CREATE_SHARED_LIBRARY} \"${ANDROID_SYSROOT}/usr/lib/crtbegin_so.o\"" ) - set( CMAKE_CXX_CREATE_SHARED_MODULE "${CMAKE_CXX_CREATE_SHARED_MODULE} \"${ANDROID_SYSROOT}/usr/lib/crtbegin_so.o\"" ) - endif() if( EXISTS "${__libstl}" ) set( CMAKE_CXX_CREATE_SHARED_LIBRARY "${CMAKE_CXX_CREATE_SHARED_LIBRARY} \"${__libstl}\"" ) set( CMAKE_CXX_CREATE_SHARED_MODULE "${CMAKE_CXX_CREATE_SHARED_MODULE} \"${__libstl}\"" ) @@ -1242,9 +1355,12 @@ if( EXISTS "${__libstl}" OR EXISTS "${__libsupcxx}" ) set( CMAKE_C_LINK_EXECUTABLE "${CMAKE_C_LINK_EXECUTABLE} \"${__libsupcxx}\"" ) endif() if( ANDROID_STL MATCHES "gnustl" ) - set( CMAKE_CXX_CREATE_SHARED_LIBRARY "${CMAKE_CXX_CREATE_SHARED_LIBRARY} -lm" ) - set( CMAKE_CXX_CREATE_SHARED_MODULE "${CMAKE_CXX_CREATE_SHARED_MODULE} -lm" ) - set( CMAKE_CXX_LINK_EXECUTABLE "${CMAKE_CXX_LINK_EXECUTABLE} -lm" ) + if( NOT EXISTS "${ANDROID_LIBM_PATH}" ) + set( ANDROID_LIBM_PATH -lm ) + endif() + set( CMAKE_CXX_CREATE_SHARED_LIBRARY "${CMAKE_CXX_CREATE_SHARED_LIBRARY} ${ANDROID_LIBM_PATH}" ) + set( CMAKE_CXX_CREATE_SHARED_MODULE "${CMAKE_CXX_CREATE_SHARED_MODULE} ${ANDROID_LIBM_PATH}" ) + set( CMAKE_CXX_LINK_EXECUTABLE "${CMAKE_CXX_LINK_EXECUTABLE} ${ANDROID_LIBM_PATH}" ) endif() endif() @@ -1280,7 +1396,14 @@ if( ARMEABI_V7A ) endif() if( ANDROID_NO_UNDEFINED ) - set( ANDROID_LINKER_FLAGS "${ANDROID_LINKER_FLAGS} -Wl,--no-undefined" ) + if( MIPS ) + # there is some sysroot-related problem in mips linker... + if( NOT ANDROID_SYSROOT MATCHES "[ ;\"]" ) + set( ANDROID_LINKER_FLAGS "${ANDROID_LINKER_FLAGS} -Wl,--no-undefined -Wl,-rpath-link,${ANDROID_SYSROOT}/usr/lib" ) + endif() + else() + set( ANDROID_LINKER_FLAGS "${ANDROID_LINKER_FLAGS} -Wl,--no-undefined" ) + endif() endif() if( ANDROID_SO_UNDEFINED ) @@ -1327,9 +1450,6 @@ if( ANDROID_COMPILER_IS_CLANG ) set( ANDROID_CXX_FLAGS "-target ${ANDROID_LLVM_TRIPLE} ${ANDROID_CXX_FLAGS}" ) endif() if( BUILD_WITH_ANDROID_NDK ) - if(ANDROID_ARCH_NAME STREQUAL "arm" ) - set( ANDROID_CXX_FLAGS "-isystem ${ANDROID_CLANG_TOOLCHAIN_ROOT}/lib/clang/${ANDROID_CLANG_VERSION}/include ${ANDROID_CXX_FLAGS}" ) - endif() set( ANDROID_CXX_FLAGS "-gcc-toolchain ${ANDROID_TOOLCHAIN_ROOT} ${ANDROID_CXX_FLAGS}" ) endif() endif() @@ -1345,6 +1465,12 @@ set( CMAKE_SHARED_LINKER_FLAGS "" CACHE STRING "shared li set( CMAKE_MODULE_LINKER_FLAGS "" CACHE STRING "module linker flags" ) set( CMAKE_EXE_LINKER_FLAGS "-Wl,-z,nocopyreloc" CACHE STRING "executable linker flags" ) +# put flags to cache (for debug purpose only) +set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS}" CACHE INTERNAL "Android specific c/c++ flags" ) +set( ANDROID_CXX_FLAGS_RELEASE "${ANDROID_CXX_FLAGS_RELEASE}" CACHE INTERNAL "Android specific c/c++ Release flags" ) +set( ANDROID_CXX_FLAGS_DEBUG "${ANDROID_CXX_FLAGS_DEBUG}" CACHE INTERNAL "Android specific c/c++ Debug flags" ) +set( ANDROID_LINKER_FLAGS "${ANDROID_LINKER_FLAGS}" CACHE INTERNAL "Android specific c/c++ linker flags" ) + # finish flags set( CMAKE_CXX_FLAGS "${ANDROID_CXX_FLAGS} ${CMAKE_CXX_FLAGS}" ) set( CMAKE_C_FLAGS "${ANDROID_CXX_FLAGS} ${CMAKE_C_FLAGS}" ) @@ -1357,9 +1483,9 @@ set( CMAKE_MODULE_LINKER_FLAGS "${ANDROID_LINKER_FLAGS} ${CMAKE_MODULE_LINKER_FL set( CMAKE_EXE_LINKER_FLAGS "${ANDROID_LINKER_FLAGS} ${CMAKE_EXE_LINKER_FLAGS}" ) if( MIPS AND BUILD_WITH_ANDROID_NDK AND ANDROID_NDK_RELEASE STREQUAL "r8" ) - set( CMAKE_SHARED_LINKER_FLAGS "-Wl,-T,${ANDROID_NDK}/toolchains/${ANDROID_GCC_TOOLCHAIN_NAME}/mipself.xsc ${CMAKE_SHARED_LINKER_FLAGS}" ) - set( CMAKE_MODULE_LINKER_FLAGS "-Wl,-T,${ANDROID_NDK}/toolchains/${ANDROID_GCC_TOOLCHAIN_NAME}/mipself.xsc ${CMAKE_MODULE_LINKER_FLAGS}" ) - set( CMAKE_EXE_LINKER_FLAGS "-Wl,-T,${ANDROID_NDK}/toolchains/${ANDROID_GCC_TOOLCHAIN_NAME}/mipself.x ${CMAKE_EXE_LINKER_FLAGS}" ) + set( CMAKE_SHARED_LINKER_FLAGS "-Wl,-T,${ANDROID_NDK_TOOLCHAINS_PATH}/${ANDROID_GCC_TOOLCHAIN_NAME}/mipself.xsc ${CMAKE_SHARED_LINKER_FLAGS}" ) + set( CMAKE_MODULE_LINKER_FLAGS "-Wl,-T,${ANDROID_NDK_TOOLCHAINS_PATH}/${ANDROID_GCC_TOOLCHAIN_NAME}/mipself.xsc ${CMAKE_MODULE_LINKER_FLAGS}" ) + set( CMAKE_EXE_LINKER_FLAGS "-Wl,-T,${ANDROID_NDK_TOOLCHAINS_PATH}/${ANDROID_GCC_TOOLCHAIN_NAME}/mipself.x ${CMAKE_EXE_LINKER_FLAGS}" ) endif() # configure rtti @@ -1386,6 +1512,43 @@ endif() include_directories( SYSTEM "${ANDROID_SYSROOT}/usr/include" ${ANDROID_STL_INCLUDE_DIRS} ) link_directories( "${CMAKE_INSTALL_PREFIX}/libs/${ANDROID_NDK_ABI_NAME}" ) +# detect if need link crtbegin_so.o explicitly +if( NOT DEFINED ANDROID_EXPLICIT_CRT_LINK ) + set( __cmd "${CMAKE_CXX_CREATE_SHARED_LIBRARY}" ) + string( REPLACE "" "${CMAKE_CXX_COMPILER} ${CMAKE_CXX_COMPILER_ARG1}" __cmd "${__cmd}" ) + string( REPLACE "" "${CMAKE_C_COMPILER} ${CMAKE_C_COMPILER_ARG1}" __cmd "${__cmd}" ) + string( REPLACE "" "${CMAKE_CXX_FLAGS}" __cmd "${__cmd}" ) + string( REPLACE "" "" __cmd "${__cmd}" ) + string( REPLACE "" "${CMAKE_SHARED_LINKER_FLAGS}" __cmd "${__cmd}" ) + string( REPLACE "" "-shared" __cmd "${__cmd}" ) + string( REPLACE "" "" __cmd "${__cmd}" ) + string( REPLACE "" "" __cmd "${__cmd}" ) + string( REPLACE "" "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/toolchain_crtlink_test.so" __cmd "${__cmd}" ) + string( REPLACE "" "\"${ANDROID_SYSROOT}/usr/lib/crtbegin_so.o\"" __cmd "${__cmd}" ) + string( REPLACE "" "" __cmd "${__cmd}" ) + separate_arguments( __cmd ) + foreach( __var ANDROID_NDK ANDROID_NDK_TOOLCHAINS_PATH ANDROID_STANDALONE_TOOLCHAIN ) + if( ${__var} ) + set( __tmp "${${__var}}" ) + separate_arguments( __tmp ) + string( REPLACE "${__tmp}" "${${__var}}" __cmd "${__cmd}") + endif() + endforeach() + string( REPLACE "'" "" __cmd "${__cmd}" ) + string( REPLACE "\"" "" __cmd "${__cmd}" ) + execute_process( COMMAND ${__cmd} RESULT_VARIABLE __cmd_result OUTPUT_QUIET ERROR_QUIET ) + if( __cmd_result EQUAL 0 ) + set( ANDROID_EXPLICIT_CRT_LINK ON ) + else() + set( ANDROID_EXPLICIT_CRT_LINK OFF ) + endif() +endif() + +if( ANDROID_EXPLICIT_CRT_LINK ) + set( CMAKE_CXX_CREATE_SHARED_LIBRARY "${CMAKE_CXX_CREATE_SHARED_LIBRARY} \"${ANDROID_SYSROOT}/usr/lib/crtbegin_so.o\"" ) + set( CMAKE_CXX_CREATE_SHARED_MODULE "${CMAKE_CXX_CREATE_SHARED_MODULE} \"${ANDROID_SYSROOT}/usr/lib/crtbegin_so.o\"" ) +endif() + # setup output directories set( LIBRARY_OUTPUT_PATH_ROOT ${CMAKE_SOURCE_DIR} CACHE PATH "root for library output, set this to change where android libs are installed to" ) set( CMAKE_INSTALL_PREFIX "${ANDROID_TOOLCHAIN_ROOT}/user" CACHE STRING "path for installing" ) @@ -1475,7 +1638,9 @@ endmacro() if( NOT PROJECT_NAME STREQUAL "CMAKE_TRY_COMPILE" ) set( __toolchain_config "") foreach( __var NDK_CCACHE LIBRARY_OUTPUT_PATH_ROOT ANDROID_FORBID_SYGWIN ANDROID_SET_OBSOLETE_VARIABLES + ANDROID_NDK_HOST_X64 ANDROID_NDK + ANDROID_NDK_LAYOUT ANDROID_STANDALONE_TOOLCHAIN ANDROID_TOOLCHAIN_NAME ANDROID_ABI @@ -1489,6 +1654,8 @@ if( NOT PROJECT_NAME STREQUAL "CMAKE_TRY_COMPILE" ) ANDROID_GOLD_LINKER ANDROID_NOEXECSTACK ANDROID_RELRO + ANDROID_LIBM_PATH + ANDROID_EXPLICIT_CRT_LINK ) if( DEFINED ${__var} ) if( "${__var}" MATCHES " ") @@ -1531,6 +1698,8 @@ endif() # ANDROID_NDK # ANDROID_STANDALONE_TOOLCHAIN # ANDROID_TOOLCHAIN_NAME : the NDK name of compiler toolchain +# ANDROID_NDK_HOST_X64 : try to use x86_64 toolchain (default for x64 host systems) +# ANDROID_NDK_LAYOUT : the inner NDK structure (RELEASE, LINARO, ANDROID) # LIBRARY_OUTPUT_PATH_ROOT : # NDK_CCACHE : # Obsolete: @@ -1553,7 +1722,7 @@ endif() # BUILD_ANDROID : always TRUE # BUILD_WITH_ANDROID_NDK : TRUE if NDK is used # BUILD_WITH_STANDALONE_TOOLCHAIN : TRUE if standalone toolchain is used -# ANDROID_NDK_HOST_SYSTEM_NAME : "windows", "linux-x86", "linux-x86_64" or "darwin-x86" depending on host platform +# ANDROID_NDK_HOST_SYSTEM_NAME : "windows", "linux-x86" or "darwin-x86" depending on host platform # ANDROID_NDK_ABI_NAME : "armeabi", "armeabi-v7a", "x86" or "mips" depending on ANDROID_ABI # ANDROID_NDK_RELEASE : one of r5, r5b, r5c, r6, r6b, r7, r7b, r7c, r8, r8b, r8c, r8d, r8e; set only for NDK # ANDROID_ARCH_NAME : "arm" or "x86" or "mips" depending on ANDROID_ABI @@ -1576,6 +1745,7 @@ endif() # ANDROID_EXCEPTIONS : if exceptions are enabled by the runtime # ANDROID_GCC_TOOLCHAIN_NAME : read-only, differs from ANDROID_TOOLCHAIN_NAME only if clang is used # ANDROID_CLANG_VERSION : version of clang compiler if clang is used +# ANDROID_LIBM_PATH : path to libm.so (set to something like $(TOP)/out/target/product//obj/lib/libm.so) to workaround unresolved `sincos` # # Defaults: # ANDROID_DEFAULT_NDK_API_LEVEL diff --git a/cmake/FindDBus.cmake b/cmake/FindDBus.cmake new file mode 100644 index 000000000..b002a754b --- /dev/null +++ b/cmake/FindDBus.cmake @@ -0,0 +1,73 @@ +# - Try to find the low-level D-Bus library +# Once done this will define +# +# DBUS_FOUND - system has D-Bus +# DBUS_INCLUDE_DIR - the D-Bus include directory +# DBUS_ARCH_INCLUDE_DIR - the D-Bus architecture-specific include directory +# DBUS_LIBRARIES - the libraries needed to use D-Bus + +# Copyright (c) 2008, Kevin Kofler, +# modeled after FindLibArt.cmake: +# Copyright (c) 2006, Alexander Neundorf, +# +# Redistribution and use is allowed according to the terms of the BSD license. +# For details see the accompanying COPYING-CMAKE-SCRIPTS file. + +if (DBUS_INCLUDE_DIR AND DBUS_ARCH_INCLUDE_DIR AND DBUS_LIBRARIES) + + # in cache already + SET(DBUS_FOUND TRUE) + +else (DBUS_INCLUDE_DIR AND DBUS_ARCH_INCLUDE_DIR AND DBUS_LIBRARIES) + + IF (NOT WIN32) + FIND_PACKAGE(PkgConfig) + IF (PKG_CONFIG_FOUND) + # use pkg-config to get the directories and then use these values + # in the FIND_PATH() and FIND_LIBRARY() calls + pkg_check_modules(_DBUS_PC QUIET dbus-1) + ENDIF (PKG_CONFIG_FOUND) + ENDIF (NOT WIN32) + + FIND_PATH(DBUS_INCLUDE_DIR dbus/dbus.h + ${_DBUS_PC_INCLUDE_DIRS} + /usr/include + /usr/include/dbus-1.0 + /usr/local/include + ) + + FIND_PATH(DBUS_ARCH_INCLUDE_DIR dbus/dbus-arch-deps.h + ${_DBUS_PC_INCLUDE_DIRS} + /usr/lib${LIB_SUFFIX}/include + /usr/lib${LIB_SUFFIX}/dbus-1.0/include + /usr/lib64/include + /usr/lib64/dbus-1.0/include + /usr/lib/include + /usr/lib/dbus-1.0/include + ) + + FIND_LIBRARY(DBUS_LIBRARIES NAMES dbus-1 dbus + PATHS + ${_DBUS_PC_LIBDIR} + ) + + + if (DBUS_INCLUDE_DIR AND DBUS_ARCH_INCLUDE_DIR AND DBUS_LIBRARIES) + set(DBUS_FOUND TRUE) + endif (DBUS_INCLUDE_DIR AND DBUS_ARCH_INCLUDE_DIR AND DBUS_LIBRARIES) + + + if (DBUS_FOUND) + if (NOT DBus_FIND_QUIETLY) + message(STATUS "Found D-Bus: ${DBUS_LIBRARIES}") + endif (NOT DBus_FIND_QUIETLY) + else (DBUS_FOUND) + if (DBus_FIND_REQUIRED) + message(FATAL_ERROR "Could NOT find D-Bus") + endif (DBus_FIND_REQUIRED) + endif (DBUS_FOUND) + + MARK_AS_ADVANCED(DBUS_INCLUDE_DIR DBUS_ARCH_INCLUDE_DIR DBUS_LIBRARIES) + +endif (DBUS_INCLUDE_DIR AND DBUS_ARCH_INCLUDE_DIR AND DBUS_LIBRARIES) + diff --git a/cmake/FindDbusGlib.cmake b/cmake/FindDbusGlib.cmake new file mode 100644 index 000000000..ae966bc65 --- /dev/null +++ b/cmake/FindDbusGlib.cmake @@ -0,0 +1,38 @@ +# DbusGlib library detection +# +# Copyright 2013 Thinstuff Technologies GmbH +# Copyright 2013 Armin Novak +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +find_package(PkgConfig) +pkg_check_modules(PC_DBUS_GLIB QUIET dbus-glib-1) +set(DBUS_GLIB_DEFINITIONS ${PC_DBUS_GLIB_CFLAGS_OTHER}) + +find_path(DBUS_GLIB_INCLUDE_DIR dbus/dbus-glib.h + HINTS ${PC_DBUS_GLIB_INCLUDEDIR} ${PC_DBUS_GLIB_INCLUDE_DIRS} + PATH_SUFFIXES dbus-glib-1 ) + +find_library(DBUS_GLIB_LIBRARY NAMES dbus-glib-1 dbus-glib + HINTS ${PC_DBUS_GLIB_LIBDIR} ${PC_DBUS_GLIB_LIBRARY_DIRS} ) + +set(DBUS_GLIB_LIBRARIES ${DBUS_GLIB_LIBRARY} ) +set(DBUS_GLIB_INCLUDE_DIRS ${DBUS_GLIB_INCLUDE_DIR} ) + +include(FindPackageHandleStandardArgs) +# handle the QUIETLY and REQUIRED arguments and set DBUS_GLIB_FOUND to TRUE +# if all listed variables are TRUE +find_package_handle_standard_args(dbus-glib DEFAULT_MSG + DBUS_GLIB_LIBRARY DBUS_GLIB_INCLUDE_DIR) + +mark_as_advanced(DBUS_GLIB_INCLUDE_DIR DBUS_GLIB_LIBRARY ) diff --git a/cmake/FindDocBookXSL.cmake b/cmake/FindDocBookXSL.cmake new file mode 100644 index 000000000..9192ef9b3 --- /dev/null +++ b/cmake/FindDocBookXSL.cmake @@ -0,0 +1,52 @@ +# Try to find DocBook XSL stylesheet +# Once done, it will define: +# +# DOCBOOKXSL_FOUND - system has the required DocBook XML DTDs +# DOCBOOKXSL_DIR - the directory containing the stylesheets +# used to process DocBook XML + +# Copyright (c) 2010, Luigi Toscano, +# +# Redistribution and use is allowed according to the terms of the BSD license. +# For details see the accompanying COPYING-CMAKE-SCRIPTS file. + +set (STYLESHEET_PATH_LIST + share/xml/docbook/stylesheet/docbook-xsl + share/xml/docbook/xsl-stylesheets + share/sgml/docbook/xsl-stylesheets + share/xml/docbook/stylesheet/nwalsh/current + share/xml/docbook/stylesheet/nwalsh + share/xsl/docbook + share/xsl/docbook-xsl +) + +find_path (DOCBOOKXSL_DIR lib/lib.xsl + PATHS ${CMAKE_SYSTEM_PREFIX_PATH} + PATH_SUFFIXES ${STYLESHEET_PATH_LIST} +) + +if (NOT DOCBOOKXSL_DIR) + # hacks for systems that put the version in the stylesheet dirs + set (STYLESHEET_PATH_LIST) + foreach (STYLESHEET_PREFIX_ITER ${CMAKE_SYSTEM_PREFIX_PATH}) + file(GLOB STYLESHEET_SUFFIX_ITER RELATIVE ${STYLESHEET_PREFIX_ITER} + ${STYLESHEET_PREFIX_ITER}/share/xml/docbook/xsl-stylesheets-* + ) + if (STYLESHEET_SUFFIX_ITER) + list (APPEND STYLESHEET_PATH_LIST ${STYLESHEET_SUFFIX_ITER}) + endif () + endforeach () + + find_path (DOCBOOKXSL_DIR VERSION + PATHS ${CMAKE_SYSTEM_PREFIX_PATH} + PATH_SUFFIXES ${STYLESHEET_PATH_LIST} + ) +endif (NOT DOCBOOKXSL_DIR) + + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args (DocBookXSL + "Could NOT find DocBook XSL stylesheets" + DOCBOOKXSL_DIR) + +mark_as_advanced (DOCBOOKXSL_DIR) diff --git a/cmake/FindUDev.cmake b/cmake/FindUDev.cmake new file mode 100644 index 000000000..f16761572 --- /dev/null +++ b/cmake/FindUDev.cmake @@ -0,0 +1,53 @@ +# razor-de: Configure libudev environment +# +# UDEV_FOUND - system has a libudev +# UDEV_INCLUDE_DIR - where to find header files +# UDEV_LIBRARIES - the libraries to link against udev +# UDEV_STABLE - it's true when is the version greater or equals to 143 - version when the libudev was stabilized in its API +# +# copyright (c) 2011 Petr Vanek +# Redistribution and use is allowed according to the terms of the BSD license. +# + +FIND_PATH( + UDEV_INCLUDE_DIR + libudev.h + /usr/include + /usr/local/include + ${UDEV_PATH_INCLUDES} +) + +FIND_LIBRARY( + UDEV_LIBRARIES + NAMES udev libudev + PATHS + /usr/lib${LIB_SUFFIX} + /usr/local/lib${LIB_SUFFIX} + ${UDEV_PATH_LIB} +) + +IF (UDEV_LIBRARIES AND UDEV_INCLUDE_DIR) + SET(UDEV_FOUND "YES") + execute_process(COMMAND pkg-config --atleast-version=143 libudev RESULT_VARIABLE UDEV_STABLE) + # retvale is 0 of the condition is "true" so we need to negate the value... + if (UDEV_STABLE) +set(UDEV_STABLE 0) + else (UDEV_STABLE) +set(UDEV_STABLE 1) + endif (UDEV_STABLE) + message(STATUS "libudev stable: ${UDEV_STABLE}") +ENDIF (UDEV_LIBRARIES AND UDEV_INCLUDE_DIR) + +IF (UDEV_FOUND) + MESSAGE(STATUS "Found UDev: ${UDEV_LIBRARIES}") + MESSAGE(STATUS " include: ${UDEV_INCLUDE_DIR}") +ELSE (UDEV_FOUND) + MESSAGE(STATUS "UDev not found.") + MESSAGE(STATUS "UDev: You can specify includes: -DUDEV_PATH_INCLUDES=/opt/udev/include") + MESSAGE(STATUS " currently found includes: ${UDEV_INCLUDE_DIR}") + MESSAGE(STATUS "UDev: You can specify libs: -DUDEV_PATH_LIB=/opt/udev/lib") + MESSAGE(STATUS " currently found libs: ${UDEV_LIBRARIES}") + IF (UDev_FIND_REQUIRED) + MESSAGE(FATAL_ERROR "Could not find UDev library") + ENDIF (UDev_FIND_REQUIRED) +ENDIF (UDEV_FOUND) diff --git a/cmake/FindUUID.cmake b/cmake/FindUUID.cmake new file mode 100644 index 000000000..330e5caba --- /dev/null +++ b/cmake/FindUUID.cmake @@ -0,0 +1,113 @@ +# - Try to find UUID +# Once done this will define +# +# UUID_FOUND - system has UUID +# UUID_INCLUDE_DIRS - the UUID include directory +# UUID_LIBRARIES - Link these to use UUID +# UUID_DEFINITIONS - Compiler switches required for using UUID +# +# Copyright (c) 2006 Andreas Schneider +# +# Redistribution and use is allowed according to the terms of the New +# BSD license. +# For details see the accompanying COPYING-CMAKE-SCRIPTS file. +# + + +if (UUID_LIBRARIES AND UUID_INCLUDE_DIRS) +# in cache already +set(UUID_FOUND TRUE) +else (UUID_LIBRARIES AND UUID_INCLUDE_DIRS) +find_path(UUID_INCLUDE_DIR +NAMES +uuid/uuid.h +PATHS +${UUID_DIR}/include +$ENV{UUID_DIR}/include +$ENV{UUID_DIR} +${DELTA3D_EXT_DIR}/inc +$ENV{DELTA_ROOT}/ext/inc +$ENV{DELTA_ROOT} +~/Library/Frameworks +/Library/Frameworks +/usr/local/include +/usr/include +/usr/include/gdal +/sw/include # Fink +/opt/local/include # DarwinPorts +/opt/csw/include # Blastwave +/opt/include +[HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Control\\Session\ Manager\\Environment;OSG_ROOT]/include +/usr/freeware/include + +) + +find_library(UUID_LIBRARY +NAMES +uuid +PATHS +${UUID_DIR}/lib +$ENV{UUID_DIR}/lib +$ENV{UUID_DIR} +${DELTA3D_EXT_DIR}/lib +$ENV{DELTA_ROOT}/ext/lib +$ENV{DELTA_ROOT} +$ENV{OSG_ROOT}/lib +~/Library/Frameworks +/Library/Frameworks +/usr/local/lib +/usr/lib +/sw/lib +/opt/local/lib +/opt/csw/lib +/opt/lib +/usr/freeware/lib64 +) + +find_library(UUID_LIBRARY_DEBUG +NAMES +uuidd +PATHS +${UUID_DIR}/lib +$ENV{UUID_DIR}/lib +$ENV{UUID_DIR} +${DELTA3D_EXT_DIR}/lib +$ENV{DELTA_ROOT}/ext/lib +$ENV{DELTA_ROOT} +$ENV{OSG_ROOT}/lib +~/Library/Frameworks +/Library/Frameworks +/usr/local/lib +/usr/lib +/sw/lib +/opt/local/lib +/opt/csw/lib +/opt/lib +/usr/freeware/lib64 +) + +set(UUID_INCLUDE_DIRS +${UUID_INCLUDE_DIR} +) +set(UUID_LIBRARIES +${UUID_LIBRARY} +) + +if (UUID_INCLUDE_DIRS AND UUID_LIBRARIES) +set(UUID_FOUND TRUE) +endif (UUID_INCLUDE_DIRS AND UUID_LIBRARIES) + +if (UUID_FOUND) +if (NOT UUID_FIND_QUIETLY) +message(STATUS "Found UUID: ${UUID_LIBRARIES}") +endif (NOT UUID_FIND_QUIETLY) +else (UUID_FOUND) +if (UUID_FIND_REQUIRED) +message(FATAL_ERROR "Could not find UUID") +endif (UUID_FIND_REQUIRED) +endif (UUID_FOUND) + +# show the UUID_INCLUDE_DIRS and UUID_LIBRARIES variables only in the advanced view +mark_as_advanced(UUID_INCLUDE_DIRS UUID_LIBRARIES) + +endif (UUID_LIBRARIES AND UUID_INCLUDE_DIRS) diff --git a/cmake/Findlibusb-1.0.cmake b/cmake/Findlibusb-1.0.cmake new file mode 100644 index 000000000..0163bd521 --- /dev/null +++ b/cmake/Findlibusb-1.0.cmake @@ -0,0 +1,98 @@ +# - Try to find libusb-1.0 +# Once done this will define +# +# LIBUSB_1_FOUND - system has libusb +# LIBUSB_1_INCLUDE_DIRS - the libusb include directory +# LIBUSB_1_LIBRARIES - Link these to use libusb +# LIBUSB_1_DEFINITIONS - Compiler switches required for using libusb +# +# Adapted from cmake-modules Google Code project +# +# Copyright (c) 2006 Andreas Schneider +# +# (Changes for libusb) Copyright (c) 2008 Kyle Machulis +# +# Redistribution and use is allowed according to the terms of the New BSD license. +# +# CMake-Modules Project New BSD License +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# * Neither the name of the CMake-Modules Project nor the names of its +# contributors may be used to endorse or promote products derived from this +# software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +# ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# + + +if (LIBUSB_1_LIBRARIES AND LIBUSB_1_INCLUDE_DIRS) + # in cache already + set(LIBUSB_FOUND TRUE) +else (LIBUSB_1_LIBRARIES AND LIBUSB_1_INCLUDE_DIRS) + find_path(LIBUSB_1_INCLUDE_DIR + NAMES +libusb.h + PATHS + /usr/include + /usr/local/include + /opt/local/include + /sw/include +PATH_SUFFIXES +libusb-1.0 + ) + + find_library(LIBUSB_1_LIBRARY + NAMES + usb-1.0 usb + PATHS + /usr/lib + /usr/local/lib + /opt/local/lib + /sw/lib + ) + + set(LIBUSB_1_INCLUDE_DIRS + ${LIBUSB_1_INCLUDE_DIR} + ) + set(LIBUSB_1_LIBRARIES + ${LIBUSB_1_LIBRARY} +) + + if (LIBUSB_1_INCLUDE_DIRS AND LIBUSB_1_LIBRARIES) + set(LIBUSB_1_FOUND TRUE) + endif (LIBUSB_1_INCLUDE_DIRS AND LIBUSB_1_LIBRARIES) + + if (LIBUSB_1_FOUND) + if (NOT libusb_1_FIND_QUIETLY) + message(STATUS "Found libusb-1.0:") +message(STATUS " - Includes: ${LIBUSB_1_INCLUDE_DIRS}") +message(STATUS " - Libraries: ${LIBUSB_1_LIBRARIES}") + endif (NOT libusb_1_FIND_QUIETLY) + else (LIBUSB_1_FOUND) + if (libusb_1_FIND_REQUIRED) + message(FATAL_ERROR "Could not find libusb") + endif (libusb_1_FIND_REQUIRED) + endif (LIBUSB_1_FOUND) + + # show the LIBUSB_1_INCLUDE_DIRS and LIBUSB_1_LIBRARIES variables only in the advanced view + mark_as_advanced(LIBUSB_1_INCLUDE_DIRS LIBUSB_1_LIBRARIES) + +endif (LIBUSB_1_LIBRARIES AND LIBUSB_1_INCLUDE_DIRS) diff --git a/cmake/today.cmake b/cmake/today.cmake new file mode 100644 index 000000000..51d0031a8 --- /dev/null +++ b/cmake/today.cmake @@ -0,0 +1,16 @@ +# This script returns the current date in ISO format +# +# YYYY-MM-DD +# +MACRO (TODAY RESULT) + IF (WIN32) + EXECUTE_PROCESS(COMMAND "cmd" " /C date +%Y-%m-%d" OUTPUT_VARIABLE ${RESULT}) + string(REGEX REPLACE "(..)/(..)/..(..).*" "\\1/\\2/\\3" ${RESULT} ${${RESULT}}) + ELSEIF(UNIX) + EXECUTE_PROCESS(COMMAND "date" "+%Y-%m-%d" OUTPUT_VARIABLE ${RESULT}) + string(REGEX REPLACE "(..)/(..)/..(..).*" "\\1/\\2/\\3" ${RESULT} ${${RESULT}}) + ELSE (WIN32) + MESSAGE(SEND_ERROR "date not implemented") + SET(${RESULT} 000000) + ENDIF (WIN32) +ENDMACRO (TODAY) diff --git a/docs/README.android b/docs/README.android index 44a4dbd67..e83af9107 100644 --- a/docs/README.android +++ b/docs/README.android @@ -34,8 +34,8 @@ However, any other static build should work as well. To build openssl: -git clone git@github.com:bmiklautz/Android-external-openssl-ndk-static.git -cd Android-external-openssl-ndk-static +git clone git@github.com:bmiklautz/android-external-openssl-ndk-static.git +cd android-external-openssl-ndk-static ndk-build # found in the Android NDK diff --git a/libfreerdp/codec/rfx.c b/libfreerdp/codec/rfx.c index 26825a89d..54a71bcfd 100644 --- a/libfreerdp/codec/rfx.c +++ b/libfreerdp/codec/rfx.c @@ -227,6 +227,8 @@ RFX_CONTEXT* rfx_context_new(void) if (context->priv->MaxThreadCount) SetThreadpoolThreadMaximum(context->priv->ThreadPool, context->priv->MaxThreadCount); + + context->priv->EncoderStreamPool = StreamPool_New(TRUE, 64*64*3+19); } /* initialize the default pixel format */ @@ -261,6 +263,7 @@ void rfx_context_free(RFX_CONTEXT* context) { CloseThreadpool(context->priv->ThreadPool); DestroyThreadpoolEnvironment(&context->priv->ThreadPoolEnv); + StreamPool_Free(context->priv->EncoderStreamPool); #ifdef WITH_PROFILER fprintf(stderr, "\nWARNING: Profiling results probably unusable with multithreaded RemoteFX codec!\n"); #endif @@ -312,8 +315,7 @@ RFX_TILE* rfx_tile_pool_take(RFX_CONTEXT* context) { RFX_TILE* tile = NULL; - if (WaitForSingleObject(Queue_Event(context->priv->TilePool), 0) == WAIT_OBJECT_0) - tile = Queue_Dequeue(context->priv->TilePool); + tile = Queue_Dequeue(context->priv->TilePool); if (!tile) { @@ -583,17 +585,17 @@ static BOOL rfx_process_message_tile(RFX_CONTEXT* context, RFX_TILE* tile, wStre tile->data, 64 * 4); } -struct _RFX_TILE_WORK_PARAM +struct _RFX_TILE_PROCESS_WORK_PARAM { wStream s; RFX_TILE* tile; RFX_CONTEXT* context; }; -typedef struct _RFX_TILE_WORK_PARAM RFX_TILE_WORK_PARAM; +typedef struct _RFX_TILE_PROCESS_WORK_PARAM RFX_TILE_PROCESS_WORK_PARAM; void CALLBACK rfx_process_message_tile_work_callback(PTP_CALLBACK_INSTANCE instance, void* context, PTP_WORK work) { - RFX_TILE_WORK_PARAM* param = (RFX_TILE_WORK_PARAM*) context; + RFX_TILE_PROCESS_WORK_PARAM* param = (RFX_TILE_PROCESS_WORK_PARAM*) context; rfx_process_message_tile(param->context, param->tile, &(param->s)); } @@ -608,7 +610,7 @@ static BOOL rfx_process_message_tileset(RFX_CONTEXT* context, RFX_MESSAGE* messa UINT32 blockType; UINT32 tilesDataSize; PTP_WORK* work_objects = NULL; - RFX_TILE_WORK_PARAM* params = NULL; + RFX_TILE_PROCESS_WORK_PARAM* params = NULL; if (Stream_GetRemainingLength(s) < 14) { @@ -692,7 +694,7 @@ static BOOL rfx_process_message_tileset(RFX_CONTEXT* context, RFX_MESSAGE* messa if (context->priv->UseThreads) { work_objects = (PTP_WORK*) malloc(sizeof(PTP_WORK) * message->num_tiles); - params = (RFX_TILE_WORK_PARAM*) malloc(sizeof(RFX_TILE_WORK_PARAM) * message->num_tiles); + params = (RFX_TILE_PROCESS_WORK_PARAM*) malloc(sizeof(RFX_TILE_PROCESS_WORK_PARAM) * message->num_tiles); } /* tiles */ @@ -1044,6 +1046,41 @@ static void rfx_compose_message_tile(RFX_CONTEXT* context, wStream* s, Stream_SetPosition(s, end_pos); } + +struct _RFX_TILE_COMPOSE_WORK_PARAM +{ + RFX_CONTEXT* context; + wStream *s; + BYTE* tile_data; + int tile_width; + int tile_height; + int rowstride; + UINT32* quantVals; + int quantIdxY; + int quantIdxCb; + int quantIdxCr; + int xIdx; + int yIdx; +}; +typedef struct _RFX_TILE_COMPOSE_WORK_PARAM RFX_TILE_COMPOSE_WORK_PARAM; + +void CALLBACK rfx_compose_message_tile_work_callback(PTP_CALLBACK_INSTANCE instance, void* context, PTP_WORK work) +{ + RFX_TILE_COMPOSE_WORK_PARAM* param = (RFX_TILE_COMPOSE_WORK_PARAM*) context; + + /** + * Some component of the encoder chain (I suspect the rlgr encoder) expects + * the output buffer to be zeroed. The multithreaded RemoteFX encoder uses + * wStreams from the StreamPool which are reused and not zeroed out of + * course. For now, in order to prevent data corruption we clear the stream. + */ + Stream_Clear(param->s); + + rfx_compose_message_tile(param->context, param->s, + param->tile_data, param->tile_width, param->tile_height, param->rowstride, + param->quantVals, param->quantIdxY, param->quantIdxCb, param->quantIdxCr, param->xIdx, param->yIdx); +} + static void rfx_compose_message_tileset(RFX_CONTEXT* context, wStream* s, BYTE* image_data, int width, int height, int rowstride) { @@ -1062,6 +1099,11 @@ static void rfx_compose_message_tileset(RFX_CONTEXT* context, wStream* s, int xIdx; int yIdx; int tilesDataSize; + BYTE* tileData; + int tileWidth; + int tileHeight; + PTP_WORK* work_objects = NULL; + RFX_TILE_COMPOSE_WORK_PARAM* params = NULL; if (context->num_quants == 0) { @@ -1110,17 +1152,64 @@ static void rfx_compose_message_tileset(RFX_CONTEXT* context, wStream* s, DEBUG_RFX("width:%d height:%d rowstride:%d", width, height, rowstride); end_pos = Stream_GetPosition(s); + + if (context->priv->UseThreads) + { + work_objects = (PTP_WORK*) malloc(sizeof(PTP_WORK) * numTiles); + params = (RFX_TILE_COMPOSE_WORK_PARAM*) malloc(sizeof(RFX_TILE_COMPOSE_WORK_PARAM) * numTiles); + } + for (yIdx = 0; yIdx < numTilesY; yIdx++) { for (xIdx = 0; xIdx < numTilesX; xIdx++) { - rfx_compose_message_tile(context, s, - image_data + yIdx * 64 * rowstride + xIdx * 8 * context->bits_per_pixel, - (xIdx < numTilesX - 1) ? 64 : width - xIdx * 64, - (yIdx < numTilesY - 1) ? 64 : height - yIdx * 64, - rowstride, quantVals, quantIdxY, quantIdxCb, quantIdxCr, xIdx, yIdx); + tileData = image_data + yIdx * 64 * rowstride + xIdx * 8 * context->bits_per_pixel; + tileWidth = (xIdx < numTilesX - 1) ? 64 : width - xIdx * 64; + tileHeight = (yIdx < numTilesY - 1) ? 64 : height - yIdx * 64; + + if (context->priv->UseThreads) + { + i = yIdx * numTilesX + xIdx; + + params[i].context = context; + params[i].s = StreamPool_Take(context->priv->EncoderStreamPool, 0); + params[i].tile_data = tileData; + params[i].tile_width = tileWidth; + params[i].tile_height = tileHeight; + params[i].rowstride = rowstride; + params[i].quantVals = (UINT32*)quantVals; + params[i].quantIdxY = quantIdxY; + params[i].quantIdxCb = quantIdxCb; + params[i].quantIdxCr = quantIdxCr; + params[i].xIdx = xIdx; + params[i].yIdx = yIdx; + + work_objects[i] = CreateThreadpoolWork((PTP_WORK_CALLBACK) rfx_compose_message_tile_work_callback, + (void*) ¶ms[i], &context->priv->ThreadPoolEnv); + + SubmitThreadpoolWork(work_objects[i]); + } + else + { + rfx_compose_message_tile(context, s, tileData, tileWidth, tileHeight, + rowstride, quantVals, quantIdxY, quantIdxCb, quantIdxCr, xIdx, yIdx); + } } } + + if (context->priv->UseThreads) + { + for (i = 0; i < numTiles; i++) + { + WaitForThreadpoolWorkCallbacks(work_objects[i], FALSE); + CloseThreadpoolWork(work_objects[i]); + Stream_Write(s, Stream_Buffer(params[i].s), Stream_GetPosition(params[i].s)); + StreamPool_Return(context->priv->EncoderStreamPool, params[i].s); + } + free(work_objects); + free(params); + } + tilesDataSize = Stream_GetPosition(s) - end_pos; size += tilesDataSize; end_pos = Stream_GetPosition(s); diff --git a/libfreerdp/codec/rfx_types.h b/libfreerdp/codec/rfx_types.h index f87dba7f6..5b875bdba 100644 --- a/libfreerdp/codec/rfx_types.h +++ b/libfreerdp/codec/rfx_types.h @@ -49,6 +49,7 @@ struct _RFX_CONTEXT_PRIV TP_CALLBACK_ENVIRON ThreadPoolEnv; wBufferPool* BufferPool; + wStreamPool* EncoderStreamPool; /* profilers */ PROFILER_DEFINE(prof_rfx_decode_rgb); diff --git a/libfreerdp/core/connection.c b/libfreerdp/core/connection.c index 247494e07..9c4c3d756 100644 --- a/libfreerdp/core/connection.c +++ b/libfreerdp/core/connection.c @@ -194,24 +194,38 @@ BOOL rdp_client_redirect(rdpRdp* rdp) rdp_client_disconnect(rdp); /* FIXME: this is a subset of rdp_free */ + /* --> this should really go into rdp.c */ crypto_rc4_free(rdp->rc4_decrypt_key); + rdp->rc4_decrypt_key = NULL ; crypto_rc4_free(rdp->rc4_encrypt_key); + rdp->rc4_encrypt_key = NULL; crypto_des3_free(rdp->fips_encrypt); + rdp->fips_encrypt = NULL ; crypto_des3_free(rdp->fips_decrypt); + rdp->fips_decrypt = NULL ; crypto_hmac_free(rdp->fips_hmac); + rdp->fips_hmac = NULL ; + + free(settings->ServerRandom); + settings->ServerRandom = NULL ; + free(settings->ServerCertificate); + settings->ServerCertificate = NULL ; + free(settings->ClientAddress); + settings->ClientAddress = NULL ; + + mppc_enc_free(rdp->mppc_enc); + mppc_dec_free(rdp->mppc_dec); mcs_free(rdp->mcs); nego_free(rdp->nego); license_free(rdp->license); transport_free(rdp->transport); - free(settings->ServerRandom); - free(settings->ServerCertificate); - free(settings->ClientAddress); - rdp->transport = transport_new(settings); rdp->license = license_new(rdp); rdp->nego = nego_new(rdp->transport); rdp->mcs = mcs_new(rdp->transport); + rdp->mppc_dec = mppc_dec_new(); + rdp->mppc_enc = mppc_enc_new(PROTO_RDP_50); rdp->transport->layer = TRANSPORT_LAYER_TCP; settings->RedirectedSessionId = redirection->sessionID; diff --git a/libfreerdp/core/fastpath.c b/libfreerdp/core/fastpath.c index 872b57e51..844816024 100644 --- a/libfreerdp/core/fastpath.c +++ b/libfreerdp/core/fastpath.c @@ -856,6 +856,8 @@ BOOL fastpath_send_update_pdu(rdpFastPath* fastpath, BYTE updateCode, wStream* s comp_flags = FASTPATH_OUTPUT_COMPRESSION_USED; header_bytes = 7 + sec_bytes; bm = (BYTE*) (rdp->mppc_enc->outputBuffer - header_bytes); + if (comp_update) + Stream_Free(comp_update, FALSE); comp_update = Stream_New(bm, pdu_data_bytes + header_bytes); ls = comp_update; } @@ -902,6 +904,8 @@ BOOL fastpath_send_update_pdu(rdpFastPath* fastpath, BYTE updateCode, wStream* s Stream_Write_UINT16(ls, pdu_data_bytes); + if (update) + Stream_Free(update, FALSE); update = Stream_New(bm, pduLength); Stream_Seek(update, pduLength); diff --git a/libfreerdp/core/transport.c b/libfreerdp/core/transport.c index 40885442b..0f29c6ca7 100644 --- a/libfreerdp/core/transport.c +++ b/libfreerdp/core/transport.c @@ -740,7 +740,11 @@ int transport_check_fds(rdpTransport** ptransport) recv_status = transport->ReceiveCallback(transport, received, transport->ReceiveExtra); - Stream_Release(received); + if (transport == *ptransport) + /* transport might now have been freed by rdp_client_redirect and a new rdp->transport created */ + /* so only release if still valid */ + Stream_Release(received); + if (recv_status < 0) status = -1; diff --git a/winpr/CMakeLists.txt b/winpr/CMakeLists.txt index 226291f57..b4aaf45d2 100644 --- a/winpr/CMakeLists.txt +++ b/winpr/CMakeLists.txt @@ -63,11 +63,14 @@ endif() if(FREERDP_BUILD) include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include PARENT_SCOPE) + include_directories(${CMAKE_CURRENT_BINARY_DIR}/include PARENT_SCOPE) else() include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include) + include_directories(${CMAKE_CURRENT_BINARY_DIR}/include) endif() -configure_file(${CMAKE_CURRENT_SOURCE_DIR}/include/winpr/config.h.in ${CMAKE_CURRENT_SOURCE_DIR}/include/winpr/config.h) +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/include/winpr/config.h.in + ${CMAKE_CURRENT_BINARY_DIR}/include/winpr/config.h) add_subdirectory(include) diff --git a/winpr/include/winpr/collections.h b/winpr/include/winpr/collections.h index 4ef2e3b19..e6fc2bcf5 100644 --- a/winpr/include/winpr/collections.h +++ b/winpr/include/winpr/collections.h @@ -58,7 +58,7 @@ struct _wQueue int tail; int size; void** array; - HANDLE mutex; + CRITICAL_SECTION lock; HANDLE event; wObject object; @@ -67,8 +67,8 @@ typedef struct _wQueue wQueue; WINPR_API int Queue_Count(wQueue* queue); -WINPR_API BOOL Queue_Lock(wQueue* queue); -WINPR_API BOOL Queue_Unlock(wQueue* queue); +WINPR_API void Queue_Lock(wQueue* queue); +WINPR_API void Queue_Unlock(wQueue* queue); WINPR_API HANDLE Queue_Event(wQueue* queue); @@ -93,7 +93,7 @@ struct _wStack int size; int capacity; void** array; - HANDLE mutex; + CRITICAL_SECTION lock; BOOL synchronized; wObject object; }; @@ -125,7 +125,7 @@ struct _wArrayList int size; void** array; - HANDLE mutex; + CRITICAL_SECTION lock; wObject object; }; @@ -137,8 +137,8 @@ WINPR_API BOOL ArrayList_IsFixedSized(wArrayList* arrayList); WINPR_API BOOL ArrayList_IsReadOnly(wArrayList* arrayList); WINPR_API BOOL ArrayList_IsSynchronized(wArrayList* arrayList); -WINPR_API BOOL ArrayList_Lock(wArrayList* arrayList); -WINPR_API BOOL ArrayList_Unlock(wArrayList* arrayList); +WINPR_API void ArrayList_Lock(wArrayList* arrayList); +WINPR_API void ArrayList_Unlock(wArrayList* arrayList); WINPR_API void* ArrayList_GetItem(wArrayList* arrayList, int index); WINPR_API void ArrayList_SetItem(wArrayList* arrayList, int index, void* obj); @@ -165,7 +165,7 @@ WINPR_API void ArrayList_Free(wArrayList* arrayList); struct _wDictionary { BOOL synchronized; - HANDLE mutex; + CRITICAL_SECTION lock; }; typedef struct _wDictionary wDictionary; @@ -184,7 +184,7 @@ struct _wListDictionaryItem struct _wListDictionary { BOOL synchronized; - HANDLE mutex; + CRITICAL_SECTION lock; wListDictionaryItem* head; }; @@ -227,7 +227,7 @@ typedef int (*REFERENCE_FREE)(void* context, void* ptr); struct _wReferenceTable { UINT32 size; - HANDLE mutex; + CRITICAL_SECTION lock; void* context; BOOL synchronized; wReference* array; @@ -246,7 +246,7 @@ WINPR_API void ReferenceTable_Free(wReferenceTable* referenceTable); struct _wCountdownEvent { DWORD count; - HANDLE mutex; + CRITICAL_SECTION lock; HANDLE event; DWORD initialCount; }; @@ -271,7 +271,7 @@ struct _wBufferPool int size; int capacity; void** array; - HANDLE mutex; + CRITICAL_SECTION lock; int fixedSize; DWORD alignment; BOOL synchronized; @@ -292,7 +292,7 @@ struct _wObjectPool int size; int capacity; void** array; - HANDLE mutex; + CRITICAL_SECTION lock; wObject object; BOOL synchronized; }; @@ -330,7 +330,7 @@ struct _wMessageQueue int size; int capacity; wMessage* array; - HANDLE mutex; + CRITICAL_SECTION lock; HANDLE event; }; typedef struct _wMessageQueue wMessageQueue; @@ -427,7 +427,7 @@ typedef struct _wEventType wEventType; struct _wPubSub { - HANDLE mutex; + CRITICAL_SECTION lock; BOOL synchronized; int size; @@ -436,8 +436,8 @@ struct _wPubSub }; typedef struct _wPubSub wPubSub; -WINPR_API BOOL PubSub_Lock(wPubSub* pubSub); -WINPR_API BOOL PubSub_Unlock(wPubSub* pubSub); +WINPR_API void PubSub_Lock(wPubSub* pubSub); +WINPR_API void PubSub_Unlock(wPubSub* pubSub); WINPR_API wEventType* PubSub_GetEventTypes(wPubSub* pubSub, int* count); WINPR_API void PubSub_AddEventTypes(wPubSub* pubSub, wEventType* events, int count); diff --git a/winpr/include/winpr/stream.h b/winpr/include/winpr/stream.h index e9805714b..0ad45602e 100644 --- a/winpr/include/winpr/stream.h +++ b/winpr/include/winpr/stream.h @@ -24,6 +24,7 @@ #include #include #include +#include #ifdef __cplusplus extern "C" { @@ -236,7 +237,7 @@ struct _wStreamPool int uCapacity; wStream** uArray; - HANDLE mutex; + CRITICAL_SECTION lock; BOOL synchronized; size_t defaultSize; }; diff --git a/winpr/include/winpr/synch.h b/winpr/include/winpr/synch.h index c9bb0ad39..fd083ae71 100644 --- a/winpr/include/winpr/synch.h +++ b/winpr/include/winpr/synch.h @@ -139,14 +139,22 @@ typedef RTL_CONDITION_VARIABLE CONDITION_VARIABLE, *PCONDITION_VARIABLE; /* Critical Section */ +#if defined(__linux__) +/** + * Linux NPTL thread synchronization primitives are implemented using + * the futex system calls ... we can't beat futex with a spin loop. + */ +#define WINPR_CRITICAL_SECTION_DISABLE_SPINCOUNT +#endif + typedef struct _RTL_CRITICAL_SECTION { - void* DebugInfo; + PVOID DebugInfo; LONG LockCount; LONG RecursionCount; - PVOID OwningThread; - PVOID LockSemaphore; - ULONG SpinCount; + HANDLE OwningThread; + HANDLE LockSemaphore; + ULONG_PTR SpinCount; } RTL_CRITICAL_SECTION, *PRTL_CRITICAL_SECTION; typedef RTL_CRITICAL_SECTION CRITICAL_SECTION; diff --git a/winpr/libwinpr/interlocked/CMakeLists.txt b/winpr/libwinpr/interlocked/CMakeLists.txt index 9a5278112..b944c5d7c 100644 --- a/winpr/libwinpr/interlocked/CMakeLists.txt +++ b/winpr/libwinpr/interlocked/CMakeLists.txt @@ -34,7 +34,7 @@ set_target_properties(${MODULE_NAME} PROPERTIES VERSION ${WINPR_VERSION_FULL} SO set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS MONOLITHIC ${MONOLITHIC_BUILD} INTERNAL MODULE winpr - MODULES winpr-crt winpr-handle winpr-synch) + MODULES winpr-crt winpr-handle) if(MONOLITHIC_BUILD) diff --git a/winpr/libwinpr/synch/CMakeLists.txt b/winpr/libwinpr/synch/CMakeLists.txt index 1554511a6..fbc607292 100644 --- a/winpr/libwinpr/synch/CMakeLists.txt +++ b/winpr/libwinpr/synch/CMakeLists.txt @@ -18,6 +18,15 @@ set(MODULE_NAME "winpr-synch") set(MODULE_PREFIX "WINPR_SYNCH") +INCLUDE (CheckLibraryExists) +list(APPEND CMAKE_REQUIRED_DEFINITIONS -D_GNU_SOURCE) +check_library_exists(pthread pthread_tryjoin_np "" HAVE_PTHREAD_GNU_EXT) +list(REMOVE_ITEM CMAKE_REQUIRED_DEFINITIONS -D_GNU_SOURCE) + +if(HAVE_PTHREAD_GNU_EXT) + add_definitions(-D_GNU_SOURCE -DHAVE_PTHREAD_GNU_EXT) +endif(HAVE_PTHREAD_GNU_EXT) + include_directories(../thread) set(${MODULE_PREFIX}_SRCS @@ -53,7 +62,7 @@ endif() set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS MONOLITHIC ${MONOLITHIC_BUILD} INTERNAL MODULE winpr - MODULES winpr-handle) + MODULES winpr-handle winpr-interlocked winpr-thread) if(MONOLITHIC_BUILD) set(WINPR_LIBS ${WINPR_LIBS} ${${MODULE_PREFIX}_LIBS} PARENT_SCOPE) @@ -64,3 +73,6 @@ endif() set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "WinPR") +if(BUILD_TESTING) + add_subdirectory(test) +endif() diff --git a/winpr/libwinpr/synch/critical.c b/winpr/libwinpr/synch/critical.c index 560fc512a..a547bd24e 100644 --- a/winpr/libwinpr/synch/critical.c +++ b/winpr/libwinpr/synch/critical.c @@ -3,6 +3,7 @@ * Synchronization Functions * * Copyright 2012 Marc-Andre Moreau + * Copyright 2013 Norbert Federa * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -22,6 +23,9 @@ #endif #include +#include +#include +#include #include "synch.h" @@ -33,56 +37,79 @@ VOID InitializeCriticalSection(LPCRITICAL_SECTION lpCriticalSection) { - if (lpCriticalSection) - { - lpCriticalSection->DebugInfo = NULL; - - lpCriticalSection->LockCount = 0; - lpCriticalSection->RecursionCount = 0; - lpCriticalSection->SpinCount = 0; - - lpCriticalSection->OwningThread = NULL; - lpCriticalSection->LockSemaphore = NULL; - - lpCriticalSection->LockSemaphore = (winpr_sem_t*) malloc(sizeof(winpr_sem_t)); -#if defined __APPLE__ - semaphore_create(mach_task_self(), lpCriticalSection->LockSemaphore, SYNC_POLICY_FIFO, 1); -#else - sem_init(lpCriticalSection->LockSemaphore, 0, 1); -#endif - } + InitializeCriticalSectionEx(lpCriticalSection, 0, 0); } BOOL InitializeCriticalSectionEx(LPCRITICAL_SECTION lpCriticalSection, DWORD dwSpinCount, DWORD Flags) { + /** + * See http://msdn.microsoft.com/en-us/library/ff541979(v=vs.85).aspx + * - The LockCount field indicates the number of times that any thread has + * called the EnterCriticalSection routine for this critical section, + * minus one. This field starts at -1 for an unlocked critical section. + * Each call of EnterCriticalSection increments this value; each call of + * LeaveCriticalSection decrements it. + * - The RecursionCount field indicates the number of times that the owning + * thread has called EnterCriticalSection for this critical section. + */ + + if (Flags != 0) { + fprintf(stderr, "warning: InitializeCriticalSectionEx Flags unimplemented\n"); + } + + lpCriticalSection->DebugInfo = NULL; + lpCriticalSection->LockCount = -1; + lpCriticalSection->SpinCount = 0; + lpCriticalSection->RecursionCount = 0; + lpCriticalSection->OwningThread = NULL; + + lpCriticalSection->LockSemaphore = (winpr_sem_t*) malloc(sizeof(winpr_sem_t)); +#if defined(__APPLE__) + semaphore_create(mach_task_self(), lpCriticalSection->LockSemaphore, SYNC_POLICY_FIFO, 0); +#else + sem_init(lpCriticalSection->LockSemaphore, 0, 0); +#endif + + SetCriticalSectionSpinCount(lpCriticalSection, dwSpinCount); + return TRUE; } BOOL InitializeCriticalSectionAndSpinCount(LPCRITICAL_SECTION lpCriticalSection, DWORD dwSpinCount) { - return TRUE; + return InitializeCriticalSectionEx(lpCriticalSection, dwSpinCount, 0); } DWORD SetCriticalSectionSpinCount(LPCRITICAL_SECTION lpCriticalSection, DWORD dwSpinCount) { +#if !defined(WINPR_CRITICAL_SECTION_DISABLE_SPINCOUNT) + SYSTEM_INFO sysinfo; + DWORD dwPreviousSpinCount = lpCriticalSection->SpinCount; + + if (dwSpinCount) + { + /* Don't spin on uniprocessor systems! */ + GetNativeSystemInfo(&sysinfo); + if (sysinfo.dwNumberOfProcessors < 2) + dwSpinCount = 0; + } + lpCriticalSection->SpinCount = dwSpinCount; + return dwPreviousSpinCount; +#else return 0; +#endif } -VOID EnterCriticalSection(LPCRITICAL_SECTION lpCriticalSection) +VOID _WaitForCriticalSection(LPCRITICAL_SECTION lpCriticalSection) { -#if defined __APPLE__ +#if defined(__APPLE__) semaphore_wait(*((winpr_sem_t*) lpCriticalSection->LockSemaphore)); #else sem_wait((winpr_sem_t*) lpCriticalSection->LockSemaphore); #endif } -BOOL TryEnterCriticalSection(LPCRITICAL_SECTION lpCriticalSection) -{ - return TRUE; -} - -VOID LeaveCriticalSection(LPCRITICAL_SECTION lpCriticalSection) +VOID _UnWaitCriticalSection(LPCRITICAL_SECTION lpCriticalSection) { #if defined __APPLE__ semaphore_signal(*((winpr_sem_t*) lpCriticalSection->LockSemaphore)); @@ -91,13 +118,118 @@ VOID LeaveCriticalSection(LPCRITICAL_SECTION lpCriticalSection) #endif } +VOID EnterCriticalSection(LPCRITICAL_SECTION lpCriticalSection) +{ +#if !defined(WINPR_CRITICAL_SECTION_DISABLE_SPINCOUNT) + ULONG SpinCount = lpCriticalSection->SpinCount; + + /* If we're lucky or if the current thread is already owner we can return early */ + if (SpinCount && TryEnterCriticalSection(lpCriticalSection)) + return; + + /* Spin requested times but don't compete with another waiting thread */ + while (SpinCount-- && lpCriticalSection->LockCount < 1) + { + /* Atomically try to acquire and check the if the section is free. */ + if (InterlockedCompareExchange(&lpCriticalSection->LockCount, 0, -1) == -1) + { + lpCriticalSection->RecursionCount = 1; + lpCriticalSection->OwningThread = (HANDLE)GetCurrentThreadId(); + return; + } + /* Failed to get the lock. Let the scheduler know that we're spinning. */ + if (sched_yield()!=0) + { + /** + * On some operating systems sched_yield is a stub. + * usleep should at least trigger a context switch if any thread is waiting. + * A ThreadYield() would be nice in winpr ... + */ + usleep(1); + } + } + +#endif + + /* First try the fastest posssible path to get the lock. */ + if (InterlockedIncrement(&lpCriticalSection->LockCount)) + { + /* Section is already locked. Check if it is owned by the current thread. */ + if (lpCriticalSection->OwningThread == (HANDLE)GetCurrentThreadId()) + { + /* Recursion. No need to wait. */ + lpCriticalSection->RecursionCount++; + return; + } + + /* Section is locked by another thread. We have to wait. */ + _WaitForCriticalSection(lpCriticalSection); + } + /* We got the lock. Own it ... */ + lpCriticalSection->RecursionCount = 1; + lpCriticalSection->OwningThread = (HANDLE)GetCurrentThreadId(); +} + +BOOL TryEnterCriticalSection(LPCRITICAL_SECTION lpCriticalSection) +{ + HANDLE current_thread = (HANDLE)GetCurrentThreadId(); + + /* Atomically acquire the the lock if the section is free. */ + if (InterlockedCompareExchange(&lpCriticalSection->LockCount, 0, -1 ) == -1) + { + lpCriticalSection->RecursionCount = 1; + lpCriticalSection->OwningThread = current_thread; + return TRUE; + } + + /* Section is already locked. Check if it is owned by the current thread. */ + if (lpCriticalSection->OwningThread == current_thread) + { + /* Recursion, return success */ + lpCriticalSection->RecursionCount++; + InterlockedIncrement(&lpCriticalSection->LockCount); + return TRUE; + } + + return FALSE; +} + +VOID LeaveCriticalSection(LPCRITICAL_SECTION lpCriticalSection) +{ + /* Decrement RecursionCount and check if this is the last LeaveCriticalSection call ...*/ + if (--lpCriticalSection->RecursionCount < 1) + { + /* Last recursion, clear owner, unlock and if there are other waiting threads ... */ + lpCriticalSection->OwningThread = NULL; + if (InterlockedDecrement(&lpCriticalSection->LockCount) >= 0) + { + /* ...signal the semaphore to unblock the next waiting thread */ + _UnWaitCriticalSection(lpCriticalSection); + } + } + else + { + InterlockedDecrement(&lpCriticalSection->LockCount); + } +} + VOID DeleteCriticalSection(LPCRITICAL_SECTION lpCriticalSection) { + lpCriticalSection->LockCount = -1; + lpCriticalSection->SpinCount = 0; + lpCriticalSection->RecursionCount = 0; + lpCriticalSection->OwningThread = NULL; + + if (lpCriticalSection->LockSemaphore != NULL) + { #if defined __APPLE__ - semaphore_destroy(mach_task_self(), *((winpr_sem_t*) lpCriticalSection->LockSemaphore)); + semaphore_destroy(mach_task_self(), *((winpr_sem_t*) lpCriticalSection->LockSemaphore)); #else - sem_destroy((winpr_sem_t*) lpCriticalSection->LockSemaphore); + sem_destroy((winpr_sem_t*) lpCriticalSection->LockSemaphore); #endif + free(lpCriticalSection->LockSemaphore); + lpCriticalSection->LockSemaphore = NULL; + } } #endif diff --git a/winpr/libwinpr/synch/test/.gitignore b/winpr/libwinpr/synch/test/.gitignore new file mode 100644 index 000000000..7107fa9df --- /dev/null +++ b/winpr/libwinpr/synch/test/.gitignore @@ -0,0 +1,3 @@ +TestSynch +TestSynch.c + diff --git a/winpr/libwinpr/synch/test/CMakeLists.txt b/winpr/libwinpr/synch/test/CMakeLists.txt new file mode 100644 index 000000000..d26d32935 --- /dev/null +++ b/winpr/libwinpr/synch/test/CMakeLists.txt @@ -0,0 +1,31 @@ + +set(MODULE_NAME "TestSynch") +set(MODULE_PREFIX "TEST_SYNCH") + +set(${MODULE_PREFIX}_DRIVER ${MODULE_NAME}.c) + +set(${MODULE_PREFIX}_TESTS + TestSynchCritical.c) + +create_test_sourcelist(${MODULE_PREFIX}_SRCS + ${${MODULE_PREFIX}_DRIVER} + ${${MODULE_PREFIX}_TESTS}) + +add_executable(${MODULE_NAME} ${${MODULE_PREFIX}_SRCS}) + +set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS + MONOLITHIC ${MONOLITHIC_BUILD} + MODULE winpr + MODULES winpr-synch winpr-sysinfo) + +target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) + +set_target_properties(${MODULE_NAME} PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${TESTING_OUTPUT_DIRECTORY}") + +foreach(test ${${MODULE_PREFIX}_TESTS}) + get_filename_component(TestName ${test} NAME_WE) + add_test(${TestName} ${TESTING_OUTPUT_DIRECTORY}/${MODULE_NAME} ${TestName}) +endforeach() + +set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "WinPR/Test") + diff --git a/winpr/libwinpr/synch/test/TestSynchCritical.c b/winpr/libwinpr/synch/test/TestSynchCritical.c new file mode 100644 index 000000000..6ec5ca284 --- /dev/null +++ b/winpr/libwinpr/synch/test/TestSynchCritical.c @@ -0,0 +1,329 @@ + +#include +#include +#include +#include +#include +#include +#include + + +#define TEST_SYNC_CRITICAL_TEST1_RUNTIME_MS 500 +#define TEST_SYNC_CRITICAL_TEST1_RUNS 4 + +CRITICAL_SECTION critical; +LONG gTestValueVulnerable = 0; +LONG gTestValueSerialized = 0; + +BOOL TestSynchCritical_TriggerAndCheckRaceCondition(HANDLE OwningThread, LONG RecursionCount) +{ + /* if called unprotected this will hopefully trigger a race condition ... */ + gTestValueVulnerable++; + + if (critical.OwningThread != OwningThread) + { + printf("CriticalSection failure: OwningThread is invalid\n"); + return FALSE; + } + if (critical.RecursionCount != RecursionCount) + { + printf("CriticalSection failure: RecursionCount is invalid\n"); + return FALSE; + } + + /* ... which we try to detect using the serialized counter */ + if (gTestValueVulnerable != InterlockedIncrement(&gTestValueSerialized)) + { + printf("CriticalSection failure: Data corruption detected\n"); + return FALSE; + } + + return TRUE; +} + +/* this thread function shall increment the global dwTestValue until the PBOOL passsed in arg is FALSE */ +static PVOID TestSynchCritical_Test1(PVOID arg) +{ + int i, j, rc; + HANDLE hThread = (HANDLE)GetCurrentThreadId(); + + PBOOL pbContinueRunning = (PBOOL)arg; + + while(*pbContinueRunning) + { + EnterCriticalSection(&critical); + + rc = 1; + + if (!TestSynchCritical_TriggerAndCheckRaceCondition(hThread, rc)) + return (PVOID)1; + + /* add some random recursion level */ + j = rand()%5; + for (i=0; i 1) + dwSpinCountExpected = dwSpinCount+1; +#endif + if (dwPreviousSpinCount != dwSpinCountExpected) + { + printf("CriticalSection failure: SetCriticalSectionSpinCount returned %lu (expected: %lu)\n", dwPreviousSpinCount, dwSpinCountExpected); + goto fail; + } + + DeleteCriticalSection(&critical); + + if (dwSpinCount%2==0) + InitializeCriticalSectionAndSpinCount(&critical, dwSpinCount); + else + InitializeCriticalSectionEx(&critical, dwSpinCount, 0); + } + DeleteCriticalSection(&critical); + + + /** + * Test single-threaded recursive TryEnterCriticalSection/EnterCriticalSection/LeaveCriticalSection + * + */ + + InitializeCriticalSection(&critical); + + for (i=0; i<1000; i++) + { + if (critical.RecursionCount != i) + { + printf("CriticalSection failure: RecursionCount field is %ld instead of %d.\n", critical.RecursionCount, i); + goto fail; + } + if (i%2==0) + { + EnterCriticalSection(&critical); + } + else + { + if (TryEnterCriticalSection(&critical) == FALSE) + { + printf("CriticalSection failure: TryEnterCriticalSection failed where it should not.\n"); + goto fail; + } + } + if (critical.OwningThread != hMainThread) + { + printf("CriticalSection failure: Could not verify section ownership (loop index=%d).\n", i); + goto fail; + } + } + while (--i >= 0) + { + LeaveCriticalSection(&critical); + if (critical.RecursionCount != i) + { + printf("CriticalSection failure: RecursionCount field is %ld instead of %d.\n", critical.RecursionCount, i); + goto fail; + } + if (critical.OwningThread != (HANDLE)(i ? hMainThread : NULL)) + { + printf("CriticalSection failure: Could not verify section ownership (loop index=%d).\n", i); + goto fail; + } + } + DeleteCriticalSection(&critical); + + + /** + * Test using multiple threads modifying the same value + */ + + dwThreadCount = sysinfo.dwNumberOfProcessors > 1 ? sysinfo.dwNumberOfProcessors : 2; + + hThreads = (HANDLE*)calloc(dwThreadCount, sizeof(HANDLE)); + + for (j=0; j < TEST_SYNC_CRITICAL_TEST1_RUNS; j++) + { + dwSpinCount = j * 1000; + InitializeCriticalSectionAndSpinCount(&critical, dwSpinCount); + + gTestValueVulnerable = 0; + gTestValueSerialized = 0; + + /* the TestSynchCritical_Test1 threads shall run until bTest1Running is FALSE */ + bTest1Running = TRUE; + for (i=0; i #endif +#include + #include #include @@ -43,6 +45,18 @@ #include "../handle/handle.h" +static void ts_add_ms(struct timespec *ts, DWORD dwMilliseconds) +{ + ts->tv_sec += dwMilliseconds / 1000L; + ts->tv_nsec += (dwMilliseconds % 1000L) * 1000000L; + + while(ts->tv_nsec >= 1000000000L) + { + ts->tv_sec ++; + ts->tv_nsec -= 1000000000L; + } +} + DWORD WaitForSingleObject(HANDLE hHandle, DWORD dwMilliseconds) { ULONG Type; @@ -53,22 +67,37 @@ DWORD WaitForSingleObject(HANDLE hHandle, DWORD dwMilliseconds) if (Type == HANDLE_TYPE_THREAD) { - int status; + int status = 0; WINPR_THREAD* thread; void* thread_status = NULL; - if (dwMilliseconds != INFINITE) - fprintf(stderr, "WaitForSingleObject: timeout not implemented for thread wait\n"); - thread = (WINPR_THREAD*) Object; - status = pthread_join(thread->thread, &thread_status); + if (thread->started) + { + if (dwMilliseconds != INFINITE) + { +#if HAVE_PTHREAD_GNU_EXT + struct timespec timeout; - if (status != 0) - fprintf(stderr, "WaitForSingleObject: pthread_join failure: %d\n", status); + clock_gettime(CLOCK_REALTIME, &timeout); + ts_add_ms(&timeout, dwMilliseconds); - if (thread_status) - thread->dwExitCode = ((DWORD) (size_t) thread_status); + status = pthread_timedjoin_np(thread->thread, &thread_status, &timeout); +#else + fprintf(stderr, "[ERROR] %s: Thread timeouts not implemented.\n", __func__); + assert(0); +#endif + } + else + status = pthread_join(thread->thread, &thread_status); + + if (status != 0) + fprintf(stderr, "WaitForSingleObject: pthread_join failure: %d\n", status); + + if (thread_status) + thread->dwExitCode = ((DWORD) (size_t) thread_status); + } } else if (Type == HANDLE_TYPE_MUTEX) { @@ -76,10 +105,19 @@ DWORD WaitForSingleObject(HANDLE hHandle, DWORD dwMilliseconds) mutex = (WINPR_MUTEX*) Object; +#if HAVE_PTHREAD_GNU_EXT if (dwMilliseconds != INFINITE) - fprintf(stderr, "WaitForSingleObject: timeout not implemented for mutex wait\n"); + { + struct timespec timeout; - pthread_mutex_lock(&mutex->mutex); + clock_gettime(CLOCK_REALTIME, &timeout); + ts_add_ms(&timeout, dwMilliseconds); + + pthread_mutex_timedlock(&mutex->mutex, &timeout); + } + else +#endif + pthread_mutex_lock(&mutex->mutex); } else if (Type == HANDLE_TYPE_EVENT) { @@ -165,6 +203,8 @@ DWORD WaitForSingleObject(HANDLE hHandle, DWORD dwMilliseconds) DWORD WaitForSingleObjectEx(HANDLE hHandle, DWORD dwMilliseconds, BOOL bAlertable) { + fprintf(stderr, "[ERROR] %s: Function not implemented.\n", __func__); + assert(0); return WAIT_OBJECT_0; } @@ -186,7 +226,10 @@ DWORD WaitForMultipleObjects(DWORD nCount, const HANDLE* lpHandles, BOOL bWaitAl ZeroMemory(&timeout, sizeof(timeout)); if (bWaitAll) + { fprintf(stderr, "WaitForMultipleObjects: bWaitAll not yet implemented\n"); + assert(0); + } for (index = 0; index < nCount; index++) { @@ -261,11 +304,15 @@ DWORD WaitForMultipleObjects(DWORD nCount, const HANDLE* lpHandles, BOOL bWaitAl DWORD WaitForMultipleObjectsEx(DWORD nCount, const HANDLE* lpHandles, BOOL bWaitAll, DWORD dwMilliseconds, BOOL bAlertable) { + fprintf(stderr, "[ERROR] %s: Function not implemented.\n", __func__); + assert(0); return 0; } DWORD SignalObjectAndWait(HANDLE hObjectToSignal, HANDLE hObjectToWaitOn, DWORD dwMilliseconds, BOOL bAlertable) { + fprintf(stderr, "[ERROR] %s: Function not implemented.\n", __func__); + assert(0); return 0; } diff --git a/winpr/libwinpr/utils/collections/ArrayList.c b/winpr/libwinpr/utils/collections/ArrayList.c index 157b365b6..a337e2169 100644 --- a/winpr/libwinpr/utils/collections/ArrayList.c +++ b/winpr/libwinpr/utils/collections/ArrayList.c @@ -83,18 +83,18 @@ BOOL ArrayList_IsSynchronized(wArrayList* arrayList) * Lock access to the ArrayList */ -BOOL ArrayList_Lock(wArrayList* arrayList) +void ArrayList_Lock(wArrayList* arrayList) { - return (WaitForSingleObject(arrayList->mutex, INFINITE) == WAIT_OBJECT_0) ? TRUE : FALSE; + EnterCriticalSection(&arrayList->lock); } /** * Unlock access to the ArrayList */ -BOOL ArrayList_Unlock(wArrayList* arrayList) +void ArrayList_Unlock(wArrayList* arrayList) { - return ReleaseMutex(arrayList->mutex); + LeaveCriticalSection(&arrayList->lock); } /** @@ -164,7 +164,7 @@ void ArrayList_Clear(wArrayList* arrayList) int index; if (arrayList->synchronized) - WaitForSingleObject(arrayList->mutex, INFINITE); + EnterCriticalSection(&arrayList->lock); for (index = 0; index < arrayList->size; index++) { @@ -177,7 +177,7 @@ void ArrayList_Clear(wArrayList* arrayList) arrayList->size = 0; if (arrayList->synchronized) - ReleaseMutex(arrayList->mutex); + LeaveCriticalSection(&arrayList->lock); } /** @@ -187,10 +187,10 @@ void ArrayList_Clear(wArrayList* arrayList) BOOL ArrayList_Contains(wArrayList* arrayList, void* obj) { if (arrayList->synchronized) - WaitForSingleObject(arrayList->mutex, INFINITE); + EnterCriticalSection(&arrayList->lock); if (arrayList->synchronized) - ReleaseMutex(arrayList->mutex); + LeaveCriticalSection(&arrayList->lock); return FALSE; } @@ -204,7 +204,7 @@ int ArrayList_Add(wArrayList* arrayList, void* obj) int index; if (arrayList->synchronized) - WaitForSingleObject(arrayList->mutex, INFINITE); + EnterCriticalSection(&arrayList->lock); if (arrayList->size + 1 > arrayList->capacity) { @@ -216,7 +216,7 @@ int ArrayList_Add(wArrayList* arrayList, void* obj) index = arrayList->size; if (arrayList->synchronized) - ReleaseMutex(arrayList->mutex); + LeaveCriticalSection(&arrayList->lock); return index; } @@ -228,7 +228,7 @@ int ArrayList_Add(wArrayList* arrayList, void* obj) void ArrayList_Insert(wArrayList* arrayList, int index, void* obj) { if (arrayList->synchronized) - WaitForSingleObject(arrayList->mutex, INFINITE); + EnterCriticalSection(&arrayList->lock); if ((index >= 0) && (index < arrayList->size)) { @@ -237,7 +237,7 @@ void ArrayList_Insert(wArrayList* arrayList, int index, void* obj) } if (arrayList->synchronized) - ReleaseMutex(arrayList->mutex); + LeaveCriticalSection(&arrayList->lock); } /** @@ -250,7 +250,7 @@ void ArrayList_Remove(wArrayList* arrayList, void* obj) BOOL found = FALSE; if (arrayList->synchronized) - WaitForSingleObject(arrayList->mutex, INFINITE); + EnterCriticalSection(&arrayList->lock); for (index = 0; index < arrayList->size; index++) { @@ -265,7 +265,7 @@ void ArrayList_Remove(wArrayList* arrayList, void* obj) ArrayList_Shift(arrayList, index, -1); if (arrayList->synchronized) - ReleaseMutex(arrayList->mutex); + LeaveCriticalSection(&arrayList->lock); } /** @@ -275,7 +275,7 @@ void ArrayList_Remove(wArrayList* arrayList, void* obj) void ArrayList_RemoveAt(wArrayList* arrayList, int index) { if (arrayList->synchronized) - WaitForSingleObject(arrayList->mutex, INFINITE); + EnterCriticalSection(&arrayList->lock); if ((index >= 0) && (index < arrayList->size)) { @@ -283,7 +283,7 @@ void ArrayList_RemoveAt(wArrayList* arrayList, int index) } if (arrayList->synchronized) - ReleaseMutex(arrayList->mutex); + LeaveCriticalSection(&arrayList->lock); } /** @@ -302,7 +302,7 @@ int ArrayList_IndexOf(wArrayList* arrayList, void* obj, int startIndex, int coun BOOL found = FALSE; if (arrayList->synchronized) - WaitForSingleObject(arrayList->mutex, INFINITE); + EnterCriticalSection(&arrayList->lock); if (startIndex < 0) startIndex = 0; @@ -323,7 +323,7 @@ int ArrayList_IndexOf(wArrayList* arrayList, void* obj, int startIndex, int coun index = -1; if (arrayList->synchronized) - ReleaseMutex(arrayList->mutex); + LeaveCriticalSection(&arrayList->lock); return index; } @@ -344,7 +344,7 @@ int ArrayList_LastIndexOf(wArrayList* arrayList, void* obj, int startIndex, int BOOL found = FALSE; if (arrayList->synchronized) - WaitForSingleObject(arrayList->mutex, INFINITE); + EnterCriticalSection(&arrayList->lock); if (startIndex < 0) startIndex = 0; @@ -365,7 +365,7 @@ int ArrayList_LastIndexOf(wArrayList* arrayList, void* obj, int startIndex, int index = -1; if (arrayList->synchronized) - ReleaseMutex(arrayList->mutex); + LeaveCriticalSection(&arrayList->lock); return index; } @@ -390,7 +390,7 @@ wArrayList* ArrayList_New(BOOL synchronized) arrayList->array = (void**) malloc(sizeof(void*) * arrayList->capacity); - arrayList->mutex = CreateMutex(NULL, FALSE, NULL); + InitializeCriticalSectionAndSpinCount(&arrayList->lock, 4000); ZeroMemory(&arrayList->object, sizeof(wObject)); } @@ -402,7 +402,7 @@ void ArrayList_Free(wArrayList* arrayList) { ArrayList_Clear(arrayList); - CloseHandle(arrayList->mutex); + DeleteCriticalSection(&arrayList->lock); free(arrayList->array); free(arrayList); } diff --git a/winpr/libwinpr/utils/collections/BufferPool.c b/winpr/libwinpr/utils/collections/BufferPool.c index d10ba1360..b4f22b712 100644 --- a/winpr/libwinpr/utils/collections/BufferPool.c +++ b/winpr/libwinpr/utils/collections/BufferPool.c @@ -43,7 +43,7 @@ void* BufferPool_Take(wBufferPool* pool, int bufferSize) void* buffer = NULL; if (pool->synchronized) - WaitForSingleObject(pool->mutex, INFINITE); + EnterCriticalSection(&pool->lock); if (pool->fixedSize) { @@ -64,7 +64,7 @@ void* BufferPool_Take(wBufferPool* pool, int bufferSize) } if (pool->synchronized) - ReleaseMutex(pool->mutex); + LeaveCriticalSection(&pool->lock); return buffer; } @@ -76,7 +76,7 @@ void* BufferPool_Take(wBufferPool* pool, int bufferSize) void BufferPool_Return(wBufferPool* pool, void* buffer) { if (pool->synchronized) - WaitForSingleObject(pool->mutex, INFINITE); + EnterCriticalSection(&pool->lock); if ((pool->size + 1) >= pool->capacity) { @@ -87,7 +87,7 @@ void BufferPool_Return(wBufferPool* pool, void* buffer) pool->array[(pool->size)++] = buffer; if (pool->synchronized) - ReleaseMutex(pool->mutex); + LeaveCriticalSection(&pool->lock); } /** @@ -97,7 +97,7 @@ void BufferPool_Return(wBufferPool* pool, void* buffer) void BufferPool_Clear(wBufferPool* pool) { if (pool->synchronized) - WaitForSingleObject(pool->mutex, INFINITE); + EnterCriticalSection(&pool->lock); while (pool->size > 0) { @@ -110,7 +110,7 @@ void BufferPool_Clear(wBufferPool* pool) } if (pool->synchronized) - ReleaseMutex(pool->mutex); + LeaveCriticalSection(&pool->lock); } /** @@ -134,7 +134,7 @@ wBufferPool* BufferPool_New(BOOL synchronized, int fixedSize, DWORD alignment) pool->synchronized = synchronized; if (pool->synchronized) - pool->mutex = CreateMutex(NULL, FALSE, NULL); + InitializeCriticalSectionAndSpinCount(&pool->lock, 4000); if (!pool->fixedSize) { @@ -156,7 +156,7 @@ void BufferPool_Free(wBufferPool* pool) BufferPool_Clear(pool); if (pool->synchronized) - CloseHandle(pool->mutex); + DeleteCriticalSection(&pool->lock); free(pool->array); diff --git a/winpr/libwinpr/utils/collections/CountdownEvent.c b/winpr/libwinpr/utils/collections/CountdownEvent.c index 787c7e31b..ea50f4219 100644 --- a/winpr/libwinpr/utils/collections/CountdownEvent.c +++ b/winpr/libwinpr/utils/collections/CountdownEvent.c @@ -89,14 +89,14 @@ HANDLE CountdownEvent_WaitHandle(wCountdownEvent* countdown) void CountdownEvent_AddCount(wCountdownEvent* countdown, DWORD signalCount) { - WaitForSingleObject(countdown->mutex, INFINITE); + EnterCriticalSection(&countdown->lock); countdown->count += signalCount; if (countdown->count > 0) ResetEvent(countdown->event); - ReleaseMutex(countdown->mutex); + LeaveCriticalSection(&countdown->lock); } /** @@ -111,7 +111,7 @@ BOOL CountdownEvent_Signal(wCountdownEvent* countdown, DWORD signalCount) status = newStatus = oldStatus = FALSE; - WaitForSingleObject(countdown->mutex, INFINITE); + EnterCriticalSection(&countdown->lock); if (WaitForSingleObject(countdown->event, 0) == WAIT_OBJECT_0) oldStatus = TRUE; @@ -130,7 +130,7 @@ BOOL CountdownEvent_Signal(wCountdownEvent* countdown, DWORD signalCount) status = TRUE; } - ReleaseMutex(countdown->mutex); + LeaveCriticalSection(&countdown->lock); return status; } @@ -158,7 +158,7 @@ wCountdownEvent* CountdownEvent_New(DWORD initialCount) { countdown->count = initialCount; countdown->initialCount = initialCount; - countdown->mutex = CreateMutex(NULL, FALSE, NULL); + InitializeCriticalSectionAndSpinCount(&countdown->lock, 4000); countdown->event = CreateEvent(NULL, TRUE, FALSE, NULL); if (countdown->count == 0) @@ -170,7 +170,7 @@ wCountdownEvent* CountdownEvent_New(DWORD initialCount) void CountdownEvent_Free(wCountdownEvent* countdown) { - CloseHandle(countdown->mutex); + DeleteCriticalSection(&countdown->lock); CloseHandle(countdown->event); free(countdown); diff --git a/winpr/libwinpr/utils/collections/MessageQueue.c b/winpr/libwinpr/utils/collections/MessageQueue.c index d13916922..e7b8a5e84 100644 --- a/winpr/libwinpr/utils/collections/MessageQueue.c +++ b/winpr/libwinpr/utils/collections/MessageQueue.c @@ -69,7 +69,7 @@ BOOL MessageQueue_Wait(wMessageQueue* queue) void MessageQueue_Dispatch(wMessageQueue* queue, wMessage* message) { - WaitForSingleObject(queue->mutex, INFINITE); + EnterCriticalSection(&queue->lock); if (queue->size == queue->capacity) { @@ -100,7 +100,7 @@ void MessageQueue_Dispatch(wMessageQueue* queue, wMessage* message) if (queue->size > 0) SetEvent(queue->event); - ReleaseMutex(queue->mutex); + LeaveCriticalSection(&queue->lock); } void MessageQueue_Post(wMessageQueue* queue, void* context, UINT32 type, void* wParam, void* lParam) @@ -127,7 +127,7 @@ int MessageQueue_Get(wMessageQueue* queue, wMessage* message) if (!MessageQueue_Wait(queue)) return status; - WaitForSingleObject(queue->mutex, INFINITE); + EnterCriticalSection(&queue->lock); if (queue->size > 0) { @@ -142,7 +142,7 @@ int MessageQueue_Get(wMessageQueue* queue, wMessage* message) status = (message->id != WMQ_QUIT) ? 1 : 0; } - ReleaseMutex(queue->mutex); + LeaveCriticalSection(&queue->lock); return status; } @@ -151,7 +151,7 @@ int MessageQueue_Peek(wMessageQueue* queue, wMessage* message, BOOL remove) { int status = 0; - WaitForSingleObject(queue->mutex, INFINITE); + EnterCriticalSection(&queue->lock); if (queue->size > 0) { @@ -169,7 +169,7 @@ int MessageQueue_Peek(wMessageQueue* queue, wMessage* message, BOOL remove) } } - ReleaseMutex(queue->mutex); + LeaveCriticalSection(&queue->lock); return status; } @@ -194,7 +194,7 @@ wMessageQueue* MessageQueue_New() queue->array = (wMessage*) malloc(sizeof(wMessage) * queue->capacity); ZeroMemory(queue->array, sizeof(wMessage) * queue->capacity); - queue->mutex = CreateMutex(NULL, FALSE, NULL); + InitializeCriticalSectionAndSpinCount(&queue->lock, 4000); queue->event = CreateEvent(NULL, TRUE, FALSE, NULL); } @@ -204,7 +204,7 @@ wMessageQueue* MessageQueue_New() void MessageQueue_Free(wMessageQueue* queue) { CloseHandle(queue->event); - CloseHandle(queue->mutex); + DeleteCriticalSection(&queue->lock); free(queue->array); free(queue); diff --git a/winpr/libwinpr/utils/collections/ObjectPool.c b/winpr/libwinpr/utils/collections/ObjectPool.c index 472eba1d2..c0e36266f 100644 --- a/winpr/libwinpr/utils/collections/ObjectPool.c +++ b/winpr/libwinpr/utils/collections/ObjectPool.c @@ -43,7 +43,7 @@ void* ObjectPool_Take(wObjectPool* pool) void* obj = NULL; if (pool->synchronized) - WaitForSingleObject(pool->mutex, INFINITE); + EnterCriticalSection(&pool->lock); if (pool->size > 0) obj = pool->array[--(pool->size)]; @@ -55,7 +55,7 @@ void* ObjectPool_Take(wObjectPool* pool) } if (pool->synchronized) - ReleaseMutex(pool->mutex); + LeaveCriticalSection(&pool->lock); return obj; } @@ -67,7 +67,7 @@ void* ObjectPool_Take(wObjectPool* pool) void ObjectPool_Return(wObjectPool* pool, void* obj) { if (pool->synchronized) - WaitForSingleObject(pool->mutex, INFINITE); + EnterCriticalSection(&pool->lock); if ((pool->size + 1) >= pool->capacity) { @@ -78,7 +78,7 @@ void ObjectPool_Return(wObjectPool* pool, void* obj) pool->array[(pool->size)++] = obj; if (pool->synchronized) - ReleaseMutex(pool->mutex); + LeaveCriticalSection(&pool->lock); } /** @@ -88,7 +88,7 @@ void ObjectPool_Return(wObjectPool* pool, void* obj) void ObjectPool_Clear(wObjectPool* pool) { if (pool->synchronized) - WaitForSingleObject(pool->mutex, INFINITE); + EnterCriticalSection(&pool->lock); while (pool->size > 0) { @@ -99,7 +99,7 @@ void ObjectPool_Clear(wObjectPool* pool) } if (pool->synchronized) - ReleaseMutex(pool->mutex); + LeaveCriticalSection(&pool->lock); } /** @@ -119,7 +119,7 @@ wObjectPool* ObjectPool_New(BOOL synchronized) pool->synchronized = synchronized; if (pool->synchronized) - pool->mutex = CreateMutex(NULL, FALSE, NULL); + InitializeCriticalSectionAndSpinCount(&pool->lock, 4000); pool->size = 0; pool->capacity = 32; @@ -136,7 +136,7 @@ void ObjectPool_Free(wObjectPool* pool) ObjectPool_Clear(pool); if (pool->synchronized) - CloseHandle(pool->mutex); + DeleteCriticalSection(&pool->lock); free(pool->array); diff --git a/winpr/libwinpr/utils/collections/PubSub.c b/winpr/libwinpr/utils/collections/PubSub.c index 1236d6858..abd29098c 100644 --- a/winpr/libwinpr/utils/collections/PubSub.c +++ b/winpr/libwinpr/utils/collections/PubSub.c @@ -46,14 +46,14 @@ wEventType* PubSub_GetEventTypes(wPubSub* pubSub, int* count) * Methods */ -BOOL PubSub_Lock(wPubSub* pubSub) +void PubSub_Lock(wPubSub* pubSub) { - return (WaitForSingleObject(pubSub->mutex, INFINITE) == WAIT_OBJECT_0) ? TRUE : FALSE; + EnterCriticalSection(&pubSub->lock); } -BOOL PubSub_Unlock(wPubSub* pubSub) +void PubSub_Unlock(wPubSub* pubSub) { - return ReleaseMutex(pubSub->mutex); + LeaveCriticalSection(&pubSub->lock); } wEventType* PubSub_FindEventType(wPubSub* pubSub, const char* EventName) @@ -202,7 +202,7 @@ wPubSub* PubSub_New(BOOL synchronized) pubSub->synchronized = synchronized; if (pubSub->synchronized) - pubSub->mutex = CreateMutex(NULL, FALSE, NULL); + InitializeCriticalSectionAndSpinCount(&pubSub->lock, 4000); pubSub->count = 0; pubSub->size = 64; @@ -219,7 +219,7 @@ void PubSub_Free(wPubSub* pubSub) if (pubSub) { if (pubSub->synchronized) - CloseHandle(pubSub->mutex); + DeleteCriticalSection(&pubSub->lock); if (pubSub->events) free(pubSub->events); diff --git a/winpr/libwinpr/utils/collections/Queue.c b/winpr/libwinpr/utils/collections/Queue.c index fa33df76a..7a729622e 100644 --- a/winpr/libwinpr/utils/collections/Queue.c +++ b/winpr/libwinpr/utils/collections/Queue.c @@ -47,18 +47,18 @@ int Queue_Count(wQueue* queue) * Lock access to the ArrayList */ -BOOL Queue_Lock(wQueue* queue) +void Queue_Lock(wQueue* queue) { - return (WaitForSingleObject(queue->mutex, INFINITE) == WAIT_OBJECT_0) ? TRUE : FALSE; + EnterCriticalSection(&queue->lock); } /** * Unlock access to the ArrayList */ -BOOL Queue_Unlock(wQueue* queue) +void Queue_Unlock(wQueue* queue) { - return ReleaseMutex(queue->mutex); + LeaveCriticalSection(&queue->lock); } /** @@ -83,7 +83,7 @@ void Queue_Clear(wQueue* queue) int index; if (queue->synchronized) - WaitForSingleObject(queue->mutex, INFINITE); + EnterCriticalSection(&queue->lock); for (index = queue->head; index != queue->tail; index = (index + 1) % queue->capacity) { @@ -97,7 +97,7 @@ void Queue_Clear(wQueue* queue) queue->head = queue->tail = 0; if (queue->synchronized) - ReleaseMutex(queue->mutex); + LeaveCriticalSection(&queue->lock); } /** @@ -110,7 +110,7 @@ BOOL Queue_Contains(wQueue* queue, void* obj) BOOL found = FALSE; if (queue->synchronized) - WaitForSingleObject(queue->mutex, INFINITE); + EnterCriticalSection(&queue->lock); for (index = 0; index < queue->tail; index++) { @@ -122,7 +122,7 @@ BOOL Queue_Contains(wQueue* queue, void* obj) } if (queue->synchronized) - ReleaseMutex(queue->mutex); + LeaveCriticalSection(&queue->lock); return found; } @@ -134,7 +134,7 @@ BOOL Queue_Contains(wQueue* queue, void* obj) void Queue_Enqueue(wQueue* queue, void* obj) { if (queue->synchronized) - WaitForSingleObject(queue->mutex, INFINITE); + EnterCriticalSection(&queue->lock); if (queue->size == queue->capacity) { @@ -162,7 +162,7 @@ void Queue_Enqueue(wQueue* queue, void* obj) SetEvent(queue->event); if (queue->synchronized) - ReleaseMutex(queue->mutex); + LeaveCriticalSection(&queue->lock); } /** @@ -174,7 +174,7 @@ void* Queue_Dequeue(wQueue* queue) void* obj = NULL; if (queue->synchronized) - WaitForSingleObject(queue->mutex, INFINITE); + EnterCriticalSection(&queue->lock); if (queue->size > 0) { @@ -188,7 +188,7 @@ void* Queue_Dequeue(wQueue* queue) ResetEvent(queue->event); if (queue->synchronized) - ReleaseMutex(queue->mutex); + LeaveCriticalSection(&queue->lock); return obj; } @@ -202,13 +202,13 @@ void* Queue_Peek(wQueue* queue) void* obj = NULL; if (queue->synchronized) - WaitForSingleObject(queue->mutex, INFINITE); + EnterCriticalSection(&queue->lock); if (queue->size > 0) obj = queue->array[queue->head]; if (queue->synchronized) - ReleaseMutex(queue->mutex); + LeaveCriticalSection(&queue->lock); return obj; } @@ -243,7 +243,7 @@ wQueue* Queue_New(BOOL synchronized, int capacity, int growthFactor) queue->array = (void**) malloc(sizeof(void*) * queue->capacity); ZeroMemory(queue->array, sizeof(void*) * queue->capacity); - queue->mutex = CreateMutex(NULL, FALSE, NULL); + InitializeCriticalSectionAndSpinCount(&queue->lock, 4000); queue->event = CreateEvent(NULL, TRUE, FALSE, NULL); ZeroMemory(&queue->object, sizeof(wObject)); @@ -257,7 +257,7 @@ void Queue_Free(wQueue* queue) Queue_Clear(queue); CloseHandle(queue->event); - CloseHandle(queue->mutex); + DeleteCriticalSection(&queue->lock); free(queue->array); free(queue); } diff --git a/winpr/libwinpr/utils/collections/Reference.c b/winpr/libwinpr/utils/collections/Reference.c index 7df1c84b2..171123661 100644 --- a/winpr/libwinpr/utils/collections/Reference.c +++ b/winpr/libwinpr/utils/collections/Reference.c @@ -88,7 +88,7 @@ UINT32 ReferenceTable_Add(wReferenceTable* referenceTable, void* ptr) wReference* reference = NULL; if (referenceTable->synchronized) - WaitForSingleObject(referenceTable->mutex, INFINITE); + EnterCriticalSection(&referenceTable->lock); reference = ReferenceTable_FindEntry(referenceTable, ptr); @@ -102,7 +102,7 @@ UINT32 ReferenceTable_Add(wReferenceTable* referenceTable, void* ptr) count = ++(reference->Count); if (referenceTable->synchronized) - ReleaseMutex(referenceTable->mutex); + LeaveCriticalSection(&referenceTable->lock); return count; } @@ -113,7 +113,7 @@ UINT32 ReferenceTable_Release(wReferenceTable* referenceTable, void* ptr) wReference* reference = NULL; if (referenceTable->synchronized) - WaitForSingleObject(referenceTable->mutex, INFINITE); + EnterCriticalSection(&referenceTable->lock); reference = ReferenceTable_FindEntry(referenceTable, ptr); @@ -133,7 +133,7 @@ UINT32 ReferenceTable_Release(wReferenceTable* referenceTable, void* ptr) } if (referenceTable->synchronized) - ReleaseMutex(referenceTable->mutex); + LeaveCriticalSection(&referenceTable->lock); return count; } @@ -154,7 +154,7 @@ wReferenceTable* ReferenceTable_New(BOOL synchronized, void* context, REFERENCE_ ZeroMemory(referenceTable->array, sizeof(wReference) * referenceTable->size); referenceTable->synchronized = synchronized; - referenceTable->mutex = CreateMutex(NULL, FALSE, NULL); + InitializeCriticalSectionAndSpinCount(&referenceTable->lock, 4000); } return referenceTable; @@ -164,7 +164,7 @@ void ReferenceTable_Free(wReferenceTable* referenceTable) { if (referenceTable) { - CloseHandle(referenceTable->mutex); + DeleteCriticalSection(&referenceTable->lock); free(referenceTable->array); free(referenceTable); } diff --git a/winpr/libwinpr/utils/collections/Stack.c b/winpr/libwinpr/utils/collections/Stack.c index 383fe0de1..5ddb18088 100644 --- a/winpr/libwinpr/utils/collections/Stack.c +++ b/winpr/libwinpr/utils/collections/Stack.c @@ -84,7 +84,7 @@ BOOL Stack_Contains(wStack* stack, void* obj) void Stack_Push(wStack* stack, void* obj) { if (stack->synchronized) - WaitForSingleObject(stack->mutex, INFINITE); + EnterCriticalSection(&stack->lock); if ((stack->size + 1) >= stack->capacity) { @@ -95,7 +95,7 @@ void Stack_Push(wStack* stack, void* obj) stack->array[(stack->size)++] = obj; if (stack->synchronized) - ReleaseMutex(stack->mutex); + LeaveCriticalSection(&stack->lock); } /** @@ -107,13 +107,13 @@ void* Stack_Pop(wStack* stack) void* obj = NULL; if (stack->synchronized) - WaitForSingleObject(stack->mutex, INFINITE); + EnterCriticalSection(&stack->lock); if (stack->size > 0) obj = stack->array[--(stack->size)]; if (stack->synchronized) - ReleaseMutex(stack->mutex); + LeaveCriticalSection(&stack->lock); return obj; } @@ -127,13 +127,13 @@ void* Stack_Peek(wStack* stack) void* obj = NULL; if (stack->synchronized) - WaitForSingleObject(stack->mutex, INFINITE); + EnterCriticalSection(&stack->lock); if (stack->size > 0) obj = stack->array[stack->size]; if (stack->synchronized) - ReleaseMutex(stack->mutex); + LeaveCriticalSection(&stack->lock); return obj; } @@ -153,7 +153,7 @@ wStack* Stack_New(BOOL synchronized) stack->synchronized = synchronized; if (stack->synchronized) - stack->mutex = CreateMutex(NULL, FALSE, NULL); + InitializeCriticalSectionAndSpinCount(&stack->lock, 4000); stack->size = 0; stack->capacity = 32; @@ -168,7 +168,7 @@ void Stack_Free(wStack* stack) if (stack) { if (stack->synchronized) - CloseHandle(stack->mutex); + DeleteCriticalSection(&stack->lock); free(stack->array); diff --git a/winpr/libwinpr/utils/collections/StreamPool.c b/winpr/libwinpr/utils/collections/StreamPool.c index 1605c5332..dab11c0e2 100644 --- a/winpr/libwinpr/utils/collections/StreamPool.c +++ b/winpr/libwinpr/utils/collections/StreamPool.c @@ -44,7 +44,8 @@ void StreamPool_ShiftUsed(wStreamPool* pool, int index, int count) } else if (count < 0) { - MoveMemory(&pool->uArray[index], &pool->uArray[index - count], (pool->uSize - index) * sizeof(wStream*)); + if (pool->uSize - index + count > 0) + MoveMemory(&pool->uArray[index], &pool->uArray[index - count], (pool->uSize - index + count) * sizeof(wStream*)); pool->uSize += count; } } @@ -101,7 +102,8 @@ void StreamPool_ShiftAvailable(wStreamPool* pool, int index, int count) } else if (count < 0) { - MoveMemory(&pool->aArray[index], &pool->aArray[index - count], (pool->aSize - index) * sizeof(wStream*)); + if (pool->aSize - index + count > 0) + MoveMemory(&pool->aArray[index], &pool->aArray[index - count], (pool->aSize - index + count) * sizeof(wStream*)); pool->aSize += count; } } @@ -118,7 +120,7 @@ wStream* StreamPool_Take(wStreamPool* pool, size_t size) BOOL found = FALSE; if (pool->synchronized) - WaitForSingleObject(pool->mutex, INFINITE); + EnterCriticalSection(&pool->lock); if (size == 0) size = pool->defaultSize; @@ -153,7 +155,7 @@ wStream* StreamPool_Take(wStreamPool* pool, size_t size) StreamPool_AddUsed(pool, s); if (pool->synchronized) - ReleaseMutex(pool->mutex); + LeaveCriticalSection(&pool->lock); return s; } @@ -165,7 +167,7 @@ wStream* StreamPool_Take(wStreamPool* pool, size_t size) void StreamPool_Return(wStreamPool* pool, wStream* s) { if (pool->synchronized) - WaitForSingleObject(pool->mutex, INFINITE); + EnterCriticalSection(&pool->lock); if ((pool->aSize + 1) >= pool->aCapacity) { @@ -177,7 +179,7 @@ void StreamPool_Return(wStreamPool* pool, wStream* s) StreamPool_RemoveUsed(pool, s); if (pool->synchronized) - ReleaseMutex(pool->mutex); + LeaveCriticalSection(&pool->lock); } /** @@ -186,7 +188,7 @@ void StreamPool_Return(wStreamPool* pool, wStream* s) void StreamPool_Lock(wStreamPool* pool) { - WaitForSingleObject(pool->mutex, INFINITE); + EnterCriticalSection(&pool->lock); } /** @@ -195,7 +197,7 @@ void StreamPool_Lock(wStreamPool* pool) void StreamPool_Unlock(wStreamPool* pool) { - ReleaseMutex(pool->mutex); + LeaveCriticalSection(&pool->lock); } /** @@ -241,7 +243,7 @@ wStream* StreamPool_Find(wStreamPool* pool, BYTE* ptr) wStream* s = NULL; BOOL found = FALSE; - WaitForSingleObject(pool->mutex, INFINITE); + EnterCriticalSection(&pool->lock); for (index = 0; index < pool->uSize; index++) { @@ -254,7 +256,7 @@ wStream* StreamPool_Find(wStreamPool* pool, BYTE* ptr) } } - ReleaseMutex(pool->mutex); + LeaveCriticalSection(&pool->lock); return (found) ? s : NULL; } @@ -294,7 +296,7 @@ void StreamPool_Release(wStreamPool* pool, BYTE* ptr) void StreamPool_Clear(wStreamPool* pool) { if (pool->synchronized) - WaitForSingleObject(pool->mutex, INFINITE); + EnterCriticalSection(&pool->lock); while (pool->aSize > 0) { @@ -303,7 +305,7 @@ void StreamPool_Clear(wStreamPool* pool) } if (pool->synchronized) - ReleaseMutex(pool->mutex); + LeaveCriticalSection(&pool->lock); } /** @@ -323,8 +325,7 @@ wStreamPool* StreamPool_New(BOOL synchronized, size_t defaultSize) pool->synchronized = synchronized; pool->defaultSize = defaultSize; - if (pool->synchronized) - pool->mutex = CreateMutex(NULL, FALSE, NULL); + InitializeCriticalSectionAndSpinCount(&pool->lock, 4000); pool->aSize = 0; pool->aCapacity = 32; @@ -344,8 +345,7 @@ void StreamPool_Free(wStreamPool* pool) { StreamPool_Clear(pool); - if (pool->synchronized) - CloseHandle(pool->mutex); + DeleteCriticalSection(&pool->lock); free(pool->aArray); free(pool->uArray);