Browse Source

Merge branch 'master' into client

Julius Pfrommer 10 years ago
parent
commit
6f3d01772e

+ 9 - 1
.travis.yml

@@ -25,6 +25,10 @@ before_install:
    - sudo apt-get install -qq --no-install-recommends build-essential cmake python-lxml graphviz doxygen wget
    - wget http://security.ubuntu.com/ubuntu/pool/main/c/check/check_0.9.10-6ubuntu3_amd64.deb
    - sudo dpkg -i check_0.9.10-6ubuntu3_amd64.deb
+   - wget https://launchpad.net/ubuntu/+source/liburcu/0.8.5-1ubuntu1/+build/6513813/+files/liburcu2_0.8.5-1ubuntu1_amd64.deb
+   - wget https://launchpad.net/ubuntu/+source/liburcu/0.8.5-1ubuntu1/+build/6513813/+files/liburcu-dev_0.8.5-1ubuntu1_amd64.deb
+   - sudo dpkg -i liburcu2_0.8.5-1ubuntu1_amd64.deb
+   - sudo dpkg -i liburcu-dev_0.8.5-1ubuntu1_amd64.deb
    - sudo pip install cpp-coveralls
    - sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-4.8 20
    - sudo update-alternatives --config gcc
@@ -35,7 +39,11 @@ script:
    - mkdir -p build
    - cd build
    - echo "Cross compile build for MinGW"
-   - cmake -DCMAKE_TOOLCHAIN_FILE=../Toolchain-mingw32.cmake -DEXAMPLESERVER=ON ..
+   - cmake -DCMAKE_TOOLCHAIN_FILE=../cmake/Toolchain-mingw32.cmake -DEXAMPLESERVER=ON ..
+   - make
+   - cd .. && rm build -rf && mkdir -p build && cd build
+   - echo "Compile multithreaded version"
+   - cmake -DMULTITHREADING=ON -DEXAMPLESERVER=ON ..
    - make
    - cd .. && rm build -rf && mkdir -p build && cd build
    - echo "Only needed profile"

+ 5 - 1
CMakeLists.txt

@@ -149,8 +149,10 @@ else()
     list(APPEND lib_sources src/server/ua_nodestore.c)
 endif()
 
-add_library(open62541-objects OBJECT ${lib_sources}) # static version that exports all symbols
+add_library(open62541-objects OBJECT ${lib_sources}) 
 add_library(open62541 SHARED $<TARGET_OBJECTS:open62541-objects>)
+add_library(open62541-static STATIC $<TARGET_OBJECTS:open62541-objects>)
+SET_TARGET_PROPERTIES(open62541-static PROPERTIES OUTPUT_NAME open62541 CLEAN_DIRECT_OUTPUT 1) # static version that exports all symbols
 target_compile_definitions(open62541-objects PUBLIC UA_DYNAMIC_LINKING)
 
 ## logging
@@ -231,6 +233,8 @@ add_executable(exampleServer ${server_sources} ${exported_headers} ${generated_h
 target_link_libraries(exampleServer open62541)
 if(WIN32)
     target_link_libraries(exampleServer ws2_32)
+else()
+    target_link_libraries(exampleServer rt)
 endif(WIN32)
 if(MULTITHREADING)
     target_link_libraries(exampleServer urcu-cds urcu urcu-common pthread)

Toolchain-mingw32.cmake → cmake/Toolchain-mingw32.cmake


+ 3 - 3
include/ua_server.h

@@ -105,7 +105,7 @@ typedef struct UA_WorkItem {
  * @param work Pointer to the WorkItem that shall be added. The pointer is not
  *        freed but copied to an internal representation.
  *
- * @param time The time when the work shall be executed. If the time lies in the
+ * @param executionTime The time when the work shall be executed. If the time lies in the
  *        past, the work will be executed in the next iteration of the server's
  *        main loop
  *
@@ -116,7 +116,7 @@ typedef struct UA_WorkItem {
  * @return Upon sucess, UA_STATUSCODE_GOOD is returned. An error code otherwise.
  */
 UA_StatusCode UA_EXPORT UA_Server_addTimedWorkItem(UA_Server *server, const UA_WorkItem *work,
-                                                   UA_DateTime time, UA_Guid *resultWorkGuid);
+                                                   UA_DateTime executionTime, UA_Guid *resultWorkGuid);
 
 /**
  * @param server The server object.
@@ -261,7 +261,7 @@ typedef struct UA_ExternalNodeStore {
 } UA_ExternalNodeStore;
 
 UA_StatusCode UA_EXPORT
-UA_Server_addExternalNamespace(UA_Server *server, UA_UInt16 namespaceIndex, UA_ExternalNodeStore *nodeStore);
+UA_Server_addExternalNamespace(UA_Server *server, UA_UInt16 namespaceIndex, const UA_String *url, UA_ExternalNodeStore *nodeStore);
 
 /** @} */
 

+ 4 - 3
ports/WAGO-750-860.patch

@@ -36,14 +36,15 @@ index c785182..9e66da0 100644
  	endif()
  endif()
  
-@@ -150,8 +147,8 @@ else()
+@@ -149,10 +149,7 @@ else()
  endif()
  
- add_library(open62541-objects OBJECT ${lib_sources}) # static version that exports all symbols
+ add_library(open62541-objects OBJECT ${lib_sources}) 
 -add_library(open62541 SHARED $<TARGET_OBJECTS:open62541-objects>)
+-add_library(open62541-static STATIC $<TARGET_OBJECTS:open62541-objects>)
+-SET_TARGET_PROPERTIES(open62541-static PROPERTIES OUTPUT_NAME open62541 CLEAN_DIRECT_OUTPUT 1) # static version that exports all symbols
 -target_compile_definitions(open62541-objects PUBLIC UA_DYNAMIC_LINKING)
 +add_library(open62541 $<TARGET_OBJECTS:open62541-objects>)
-+#target_compile_definitions(open62541-objects PUBLIC UA_DYNAMIC_LINKING)
  
  ## logging
  set(UA_LOGLEVEL 400 CACHE STRING "Level at which logs shall be reported")

+ 1 - 1
src/server/ua_nodestore_concurrent.c

@@ -94,7 +94,7 @@ void UA_NodeStore_release(const UA_Node *managed) {
 #pragma GCC diagnostic pop
 #endif
 
-    if(uatomic_sub_return(&entry->refcount, 1) > 0)
+    if(uatomic_add_return(&entry->refcount, -1) > 0)
         return;
 
     node_deleteMembers(&entry->node);

+ 2 - 1
src/server/ua_server.c

@@ -62,10 +62,11 @@ void UA_Server_delete(UA_Server *server) {
     UA_NodeStore_delete(server->nodestore);
     UA_ByteString_deleteMembers(&server->serverCertificate);
     UA_Array_delete(server->endpointDescriptions, server->endpointDescriptionsSize, &UA_TYPES[UA_ENDPOINTDESCRIPTION]);
-    UA_free(server);
 #ifdef UA_MULTITHREADING
+    pthread_cond_destroy(&server->dispatchQueue_condition); // so the workers don't spin if the queue is empty
     rcu_barrier(); // wait for all scheduled call_rcu work to complete
 #endif
+    UA_free(server);
 }
 
 UA_Server * UA_Server_new(void) {

+ 1 - 0
src/server/ua_server_internal.h

@@ -57,6 +57,7 @@ struct UA_Server {
     // worker threads wait on the queue
 	struct cds_wfcq_head dispatchQueue_head;
 	struct cds_wfcq_tail dispatchQueue_tail;
+    pthread_cond_t dispatchQueue_condition; // so the workers don't spin if the queue is empty
 #endif
 
     LIST_HEAD(UA_TimedWorkList, UA_TimedWork) timedWork;

+ 22 - 4
src/server/ua_server_worker.c

@@ -1,4 +1,9 @@
 #include <stdio.h>
+#define __USE_POSIX
+#define _XOPEN_SOURCE 500
+#define __USE_POSIX199309
+#include <sys/time.h>
+#include <time.h>
 #include "ua_server_internal.h"
 
 /**
@@ -14,7 +19,7 @@
  *    all previous work has actually finished (only for multithreading)
  */
 
-#define MAXTIMEOUT 5000 // max timeout in usec until the next main loop iteration
+#define MAXTIMEOUT 50000 // max timeout in usec until the next main loop iteration
 #define BATCHSIZE 20 // max size of worklists that are dispatched to workers
 
 static void processWork(UA_Server *server, const UA_WorkItem *work, UA_Int32 workSize) {
@@ -93,6 +98,11 @@ static void * workerLoop(struct workerStartData *startInfo) {
     UA_Server *server = startInfo->server;
     UA_free(startInfo);
     
+    pthread_mutex_t mutex; // required for the condition variable
+    pthread_mutex_init(&mutex,0);
+    pthread_mutex_lock(&mutex);
+    struct timespec to;
+
     while(*server->running) {
         struct workListNode *wln = (struct workListNode*)
             cds_wfcq_dequeue_blocking(&server->dispatchQueue_head, &server->dispatchQueue_tail);
@@ -100,9 +110,15 @@ static void * workerLoop(struct workerStartData *startInfo) {
             processWork(server, wln->work, wln->workSize);
             UA_free(wln->work);
             UA_free(wln);
+        } else {
+            clock_gettime(CLOCK_REALTIME, &to);
+            to.tv_sec += 2;
+            pthread_cond_timedwait(&server->dispatchQueue_condition, &mutex, &to);
         }
         uatomic_inc(c); // increase the workerCounter;
     }
+    pthread_mutex_unlock(&mutex);
+    pthread_mutex_destroy(&mutex);
    	rcu_unregister_thread();
     return UA_NULL;
 }
@@ -184,9 +200,9 @@ static UA_StatusCode addTimedWork(UA_Server *server, const UA_WorkItem *item, UA
 }
 
 // Currently, these functions need to get the server mutex, but should be sufficiently fast
-UA_StatusCode UA_Server_addTimedWorkItem(UA_Server *server, const UA_WorkItem *work, UA_DateTime time,
+UA_StatusCode UA_Server_addTimedWorkItem(UA_Server *server, const UA_WorkItem *work, UA_DateTime executionTime,
                                          UA_Guid *resultWorkGuid) {
-    return addTimedWork(server, work, time, 0, resultWorkGuid);
+    return addTimedWork(server, work, executionTime, 0, resultWorkGuid);
 }
 
 UA_StatusCode UA_Server_addRepeatedWorkItem(UA_Server *server, const UA_WorkItem *work, UA_UInt32 interval,
@@ -392,6 +408,7 @@ UA_StatusCode UA_Server_run(UA_Server *server, UA_UInt16 nThreads, UA_Boolean *r
     // 1) Prepare the threads
     server->running = running; // the threads need to access the variable
     server->nThreads = nThreads;
+    pthread_cond_init(&server->dispatchQueue_condition, 0);
     pthread_t *thr = UA_malloc(nThreads * sizeof(pthread_t));
     server->workerCounters = UA_malloc(nThreads * sizeof(UA_UInt32 *));
     for(UA_UInt32 i=0;i<nThreads;i++) {
@@ -439,13 +456,14 @@ UA_StatusCode UA_Server_run(UA_Server *server, UA_UInt16 nThreads, UA_Boolean *r
                 work[k].type = UA_WORKITEMTYPE_NOTHING;
             }
             dispatchWork(server, workSize, work);
+            if(workSize > 0)
+                pthread_cond_broadcast(&server->dispatchQueue_condition); 
 #else
             processWork(server, work, workSize);
             UA_free(work);
 #endif
         }
 
-
         // 3.3) Exit?
         if(!*running)
             break;

+ 1 - 1
src/server/ua_services_attribute.c

@@ -372,7 +372,7 @@ static UA_StatusCode writeValue(UA_Server *server, UA_WriteValue *aWriteValue) {
             break;
 
         case UA_ATTRIBUTEID_VALUE:
-            if(newNode->nodeClass != (UA_NODECLASS_VARIABLE | UA_NODECLASS_VARIABLETYPE)) {
+            if((newNode->nodeClass != UA_NODECLASS_VARIABLE) && (newNode->nodeClass != UA_NODECLASS_VARIABLETYPE)) {
                 retval = UA_STATUSCODE_BADWRITENOTSUPPORTED;
                 break;
             }

+ 31 - 4
src/server/ua_services_view.c

@@ -226,7 +226,7 @@ static void getBrowseResult(UA_NodeStore *ns, const UA_BrowseDescription *browse
 
 void Service_Browse(UA_Server *server, UA_Session *session, const UA_BrowseRequest *request,
                     UA_BrowseResponse *response) {
-    if(request->nodesToBrowseSize <= 0) {
+   if(request->nodesToBrowseSize <= 0) {
         response->responseHeader.serviceResult = UA_STATUSCODE_BADNOTHINGTODO;
         return;
     }
@@ -237,11 +237,38 @@ void Service_Browse(UA_Server *server, UA_Session *session, const UA_BrowseReque
         response->responseHeader.serviceResult = retval;
         return;
     }
-        
+
+
+    /* ### Begin External Namespaces */
+    UA_Boolean *isExternal = UA_alloca(sizeof(UA_Boolean) * request->nodesToBrowseSize);
+    UA_memset(isExternal, UA_FALSE, sizeof(UA_Boolean) * request->nodesToBrowseSize);
+    UA_UInt32 *indices = UA_alloca(sizeof(UA_UInt32) * request->nodesToBrowseSize);
+    for(UA_Int32 j = 0;j<server->externalNamespacesSize;j++) {
+        UA_UInt32 indexSize = 0;
+        for(UA_Int32 i = 0;i < request->nodesToBrowseSize;i++) {
+            if(request->nodesToBrowse[i].nodeId.namespaceIndex != server->externalNamespaces[j].index)
+                continue;
+            isExternal[i] = UA_TRUE;
+            indices[indexSize] = i;
+            indexSize++;
+        }
+        if(indexSize == 0)
+            continue;
+
+        UA_ExternalNodeStore *ens = &server->externalNamespaces[j].externalNodeStore;
+        ens->browseNodes(ens->ensHandle, &request->requestHeader, request->nodesToBrowse,
+                       indices, indexSize, request->requestedMaxReferencesPerNode, response->results, response->diagnosticInfos);
+    }
+    /* ### End External Namespaces */
+
+
     response->resultsSize = request->nodesToBrowseSize;
-    for(UA_Int32 i = 0;i < request->nodesToBrowseSize;i++)
-        getBrowseResult(server->nodestore, &request->nodesToBrowse[i],
+    for(UA_Int32 i = 0;i < request->nodesToBrowseSize;i++){
+        if(!isExternal[i]) {
+            getBrowseResult(server->nodestore, &request->nodesToBrowse[i],
                         request->requestedMaxReferencesPerNode, &response->results[i]);
+        }
+    }
 }
 
 void Service_TranslateBrowsePathsToNodeIds(UA_Server *server, UA_Session *session,

+ 10 - 0
src/ua_types.c

@@ -264,6 +264,15 @@ UA_TYPE_AS(UA_DateTime, UA_Int64)
 #define HUNDRED_NANOSEC_PER_USEC 10LL
 #define HUNDRED_NANOSEC_PER_SEC (HUNDRED_NANOSEC_PER_USEC * 1000000LL)
 
+#ifdef __MINGW32__
+#ifndef _TIMEZONE_DEFINED
+#define _TIMEZONE_DEFINED
+struct timezone {
+  int tz_minuteswest;
+  int tz_dsttime;
+};
+#endif
+#endif
 #ifdef _WIN32
 static const unsigned __int64 epoch = 116444736000000000;
 int gettimeofday(struct timeval *tp, struct timezone *tzp);
@@ -445,6 +454,7 @@ UA_StatusCode UA_NodeId_copy(UA_NodeId const *src, UA_NodeId *dst) {
         UA_NodeId_init(dst);
         return UA_STATUSCODE_BADINTERNALERROR;
     }
+    dst->namespaceIndex = src->namespaceIndex;
     dst->identifierType = src->identifierType;
     if(retval)
         UA_NodeId_deleteMembers(dst);