diff --git a/.vscode/settings.json b/.vscode/settings.json index 71a76bb51..b7e826d7b 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -107,6 +107,21 @@ }, ], "files.associations": { - "map": "cpp" + "map": "cpp", + "sc_event_subscription.h": "c", + "sc_monitor_private.h": "c", + "sc_types.h": "c", + "sc_list.h": "c", + "sc_memory_params.h": "c", + "sc_mutex.h": "c", + "array": "c", + "bitset": "c", + "string_view": "c", + "format": "c", + "initializer_list": "c", + "ranges": "c", + "span": "c", + "regex": "c", + "sc_hash_table.h": "c" } } diff --git a/glib-2.76.4.tar.xz b/glib-2.76.4.tar.xz new file mode 100644 index 000000000..9794c86cc Binary files /dev/null and b/glib-2.76.4.tar.xz differ diff --git a/sc-memory/sc-core/include/sc-core/sc-base/sc_monitor_private.h b/sc-memory/sc-core/include/sc-core/sc-base/sc_monitor_private.h new file mode 120000 index 000000000..33c6f4b3e --- /dev/null +++ b/sc-memory/sc-core/include/sc-core/sc-base/sc_monitor_private.h @@ -0,0 +1 @@ +../../../src/sc-store/sc-base/sc_monitor_private.h \ No newline at end of file diff --git a/sc-memory/sc-core/include/sc-core/sc-base/sc_mutex_private.h b/sc-memory/sc-core/include/sc-core/sc-base/sc_mutex_private.h new file mode 120000 index 000000000..52087bcef --- /dev/null +++ b/sc-memory/sc-core/include/sc-core/sc-base/sc_mutex_private.h @@ -0,0 +1 @@ +../../../src/sc-store/sc-base/sc_mutex_private.h \ No newline at end of file diff --git a/sc-memory/sc-core/include/sc-core/sc_event_subscription.h b/sc-memory/sc-core/include/sc-core/sc_event_subscription.h index 5b8c6dd49..ffe5f1828 100644 --- a/sc-memory/sc-core/include/sc-core/sc_event_subscription.h +++ b/sc-memory/sc-core/include/sc-core/sc_event_subscription.h @@ -8,6 +8,7 @@ #define _sc_event_subscription_h_ #include "sc-core/sc_types.h" +#include "sc-core/sc-container/sc_list.h" typedef struct _sc_event_subscription_manager sc_event_subscription_manager; @@ -67,6 +68,16 @@ _SC_EXTERN sc_event_subscription * sc_event_subscription_new( sc_event_callback callback, sc_event_subscription_delete_function delete_callback); +_SC_EXTERN sc_event_subscription * sc_complex_event_subscription_new( + sc_memory_context const * ctx, + sc_addr subscription_addr, + sc_event_type event_type_addr, + sc_pointer data, + sc_event_callback callback, + sc_event_subscription_delete_function delete_callback, + sc_bool is_complex_event_subscription, + sc_list * events_list); + /*! Subscribe for events from specified sc-element. * @param ctx A sc-memory context used to create sc-event subscription. * @param subscription_addr sc-address of subscribed sc-element events. @@ -87,6 +98,17 @@ _SC_EXTERN sc_event_subscription * sc_event_subscription_with_user_new( sc_event_callback_with_user callback, sc_event_subscription_delete_function delete_callback); +_SC_EXTERN sc_event_subscription * sc_complex_event_subscription_with_user_new( + sc_memory_context const * ctx, + sc_addr subscription_addr, + sc_event_type event_type_addr, + sc_type event_element_type, + sc_pointer data, + sc_event_callback_with_user callback, + sc_event_subscription_delete_function delete_callback, + sc_bool is_complex_event_subscription, + sc_list * events_list); + /*! Destroys the specified sc-event subscription. * @param event_subscription Pointer to the sc-event subscription to be destroyed. * @return Returns SC_RESULT_OK if the operation is successful, SC_RESULT_NO otherwise. @@ -117,4 +139,5 @@ _SC_EXTERN sc_addr sc_event_subscription_get_event_type(sc_event_subscription co */ _SC_EXTERN sc_addr sc_event_subscription_get_element(sc_event_subscription const * event_subscription); +_SC_EXTERN sc_bool sc_event_subscription_is_complex(sc_event_subscription const * event_subscription); #endif diff --git a/sc-memory/sc-core/include/sc_event_queue.h b/sc-memory/sc-core/include/sc_event_queue.h new file mode 120000 index 000000000..5227c6b66 --- /dev/null +++ b/sc-memory/sc-core/include/sc_event_queue.h @@ -0,0 +1 @@ +../src/sc-store/sc-event/sc_event_queue.h \ No newline at end of file diff --git a/sc-memory/sc-core/include/sc_hash_table.h b/sc-memory/sc-core/include/sc_hash_table.h new file mode 120000 index 000000000..74c07a59a --- /dev/null +++ b/sc-memory/sc-core/include/sc_hash_table.h @@ -0,0 +1 @@ +../src/sc-store/sc-container/sc_hash_table.h \ No newline at end of file diff --git a/sc-memory/sc-core/src/sc-store/sc-base/sc_monitor_private.h b/sc-memory/sc-core/src/sc-store/sc-base/sc_monitor_private.h index d83ec4e9a..62e2112f6 100644 --- a/sc-memory/sc-core/src/sc-store/sc-base/sc_monitor_private.h +++ b/sc-memory/sc-core/src/sc-store/sc-base/sc_monitor_private.h @@ -11,7 +11,7 @@ #include "sc-core/sc-container/sc_queue.h" -#include "sc_mutex_private.h" +#include "sc-core/sc-base/sc_mutex_private.h" struct _sc_monitor { diff --git a/sc-memory/sc-core/src/sc-store/sc-event/sc_event_private.h b/sc-memory/sc-core/src/sc-store/sc-event/sc_event_private.h index 2f86ba349..2c36a6bee 100644 --- a/sc-memory/sc-core/src/sc-store/sc-event/sc_event_private.h +++ b/sc-memory/sc-core/src/sc-store/sc-event/sc_event_private.h @@ -11,6 +11,8 @@ #include "sc-core/sc_event_subscription.h" #include "sc-core/sc_types.h" +#include "sc-store/sc-base/sc_condition_private.h" +#include "sc-core/sc-container/sc_list.h" #define SC_EVENT_REQUEST_DESTROY (sc_uint32)(1 << 31) @@ -35,6 +37,22 @@ struct _sc_event_subscription sc_monitor monitor; //! Count of references (users) of this sc-event subscription sc_uint32 ref_count; + + //! flag: whether the event is complex + sc_bool is_complex_event_subscription; + //! flag for activation regulation + int counter_of_activated_events; + //! value of max activated events to activate complex event + int max_value_of_activated_events; + // counter of functions sc_event_emit and _sc_event_emission_pool_worker execution + int execution_counter; + //! condition for increasing the counter + sc_condition cond_increase; + //! condition for decreasing the counter + sc_condition cond_decrease; + + //! Events list + sc_list * events_list; }; /*! Notify about sc-element deletion. @@ -80,4 +98,15 @@ sc_result sc_event_emit_impl( sc_event_do_after_callback callback, sc_addr event_addr); +sc_result start_check_condition_to_activate_complex_event( + sc_event_subscription * complex_event_subscription, + sc_memory_context const * ctx, + sc_addr subscription_addr, + sc_event_type event_type_addr, + sc_addr connector_addr, + sc_type connector_type, + sc_addr other_addr, + sc_event_do_after_callback callback, + sc_addr event_addr); + #endif diff --git a/sc-memory/sc-core/src/sc-store/sc-event/sc_event_queue.c b/sc-memory/sc-core/src/sc-store/sc-event/sc_event_queue.c index 9972ac462..6c412d5eb 100644 --- a/sc-memory/sc-core/src/sc-store/sc-event/sc_event_queue.c +++ b/sc-memory/sc-core/src/sc-store/sc-event/sc_event_queue.c @@ -15,6 +15,8 @@ #include "sc-core/sc_memory.h" #include "sc-core/sc-base/sc_allocator.h" +#include "sc-store/sc-container/sc_struct_node.h" +#include "sc-core/sc_event_subscription.h" /*! Structure representing elementary sc-event. * @note This structure holds information required for processing events in a worker thread. @@ -95,6 +97,30 @@ void _sc_event_emission_pool_worker(sc_pointer data, sc_pointer user_data) sc_storage_end_new_process(); + sc_monitor_acquire_write(&event_subscription->monitor); + + if (!sc_event_subscription_is_complex(event_subscription) && event_subscription->events_list != null_ptr) + { + if (--event_subscription->execution_counter == 0) + { + sc_struct_node * list_node = event_subscription->events_list->begin; + + while (list_node != null_ptr && list_node != event_subscription->events_list->end) + { + sc_event_subscription * complex_event_subscription = (sc_event_subscription *)list_node->data; + + if (complex_event_subscription != null_ptr) + { + sc_monitor_acquire_write(&complex_event_subscription->monitor); + sc_cond_broadcast(&complex_event_subscription->cond_decrease); + sc_monitor_release_write(&complex_event_subscription->monitor); + } + + list_node = list_node->next; + } + } + } + sc_monitor_release_write(&event_subscription->monitor); sc_monitor_release_read(&event_subscription->monitor); end: @@ -196,7 +222,9 @@ void _sc_event_emission_manager_add( sc_type connector_type, sc_addr other_addr, sc_event_do_after_callback callback, - sc_addr event_addr) + sc_addr event_addr, + sc_memory_context const * ctx, // добавил параметр в эту функцию + sc_event_type event_type_addr) // добавил параметр в эту функцию { if (manager == null_ptr) return; @@ -207,4 +235,17 @@ void _sc_event_emission_manager_add( sc_monitor_acquire_write(&manager->pool_monitor); g_thread_pool_push(manager->thread_pool, event, null_ptr); sc_monitor_release_write(&manager->pool_monitor); + if (event_subscription->is_complex_event_subscription) + { + start_check_condition_to_activate_complex_event( + event_subscription, + ctx, // добавленный параметр + event_subscription->subscription_addr, + event_type_addr, // добавленный параметр. Наверное плохо, что такая зависисмость, это надо пересмотреть + connector_addr, + connector_type, + other_addr, + callback, + event_addr); + } } diff --git a/sc-memory/sc-core/src/sc-store/sc-event/sc_event_queue.h b/sc-memory/sc-core/src/sc-store/sc-event/sc_event_queue.h index a7ed9a4d3..642f433d5 100644 --- a/sc-memory/sc-core/src/sc-store/sc-event/sc_event_queue.h +++ b/sc-memory/sc-core/src/sc-store/sc-event/sc_event_queue.h @@ -73,6 +73,8 @@ void _sc_event_emission_manager_add( sc_type connector_type, sc_addr other_addr, sc_event_do_after_callback callback, - sc_addr event_addr); + sc_addr event_addr, + sc_memory_context const * ctx, // добавил параметр в эту функцию + sc_event_type event_type_addr); #endif diff --git a/sc-memory/sc-core/src/sc-store/sc_event_subscription.c b/sc-memory/sc-core/src/sc-store/sc_event_subscription.c index 75cbbfa92..b0c3a42da 100644 --- a/sc-memory/sc-core/src/sc-store/sc_event_subscription.c +++ b/sc-memory/sc-core/src/sc-store/sc_event_subscription.c @@ -18,6 +18,9 @@ #include "sc_memory_context_manager.h" #include "sc_memory_context_private.h" +#include "sc-store/sc-base/sc_condition_private.h" +#include "sc-core/sc-container/sc_list.h" +#include "sc-store/sc-container/sc_struct_node.h" /*! Structure representing an sc-event_subscription registration manager. * @note This structure manages the registration and removal of sc-events associated with sc-elements. @@ -130,6 +133,112 @@ void sc_event_subscription_manager_shutdown(sc_event_subscription_manager * mana sc_mem_free(manager); } +sc_event_subscription * sc_complex_event_subscription_new( + sc_memory_context const * ctx, + sc_addr subscription_addr, + sc_event_type event_type_addr, + sc_pointer data, + sc_event_callback callback, + sc_event_subscription_delete_function delete_callback, + sc_bool is_complex_event_subscription, + sc_list * events_list) +{ + sc_unused(ctx); + + if (!sc_storage_is_element(ctx, subscription_addr)) + return null_ptr; + + if (!sc_storage_is_element(ctx, event_type_addr)) + return null_ptr; + + sc_event_subscription * event_subscription = sc_mem_new(sc_event_subscription, 1); + event_subscription->subscription_addr = subscription_addr; + event_subscription->event_type_addr = event_type_addr; + event_subscription->event_element_type = 0; + event_subscription->callback = callback; + event_subscription->callback_with_user = null_ptr; + event_subscription->delete_callback = delete_callback; + event_subscription->data = data; + event_subscription->ref_count = 1; + sc_monitor_init(&event_subscription->monitor); + event_subscription->is_complex_event_subscription = is_complex_event_subscription; + event_subscription->counter_of_activated_events = 0; + if (events_list == null_ptr) + event_subscription->max_value_of_activated_events = 0; + else + event_subscription->max_value_of_activated_events = events_list->size; // + event_subscription->execution_counter = 0; + if (is_complex_event_subscription) + { + event_subscription->events_list = null_ptr; + } + else + { + event_subscription->events_list = events_list; + } + sc_cond_init(&event_subscription->cond_increase); + sc_cond_init(&event_subscription->cond_decrease); + // register generated event_subscription + sc_event_subscription_manager * manager = sc_storage_get_event_subscription_manager(); + _sc_event_subscription_manager_add(manager, event_subscription); + + return event_subscription; +} + +sc_event_subscription * sc_complex_event_subscription_with_user_new( + sc_memory_context const * ctx, + sc_addr subscription_addr, + sc_event_type event_type_addr, + sc_type event_element_type, + sc_pointer data, + sc_event_callback_with_user callback, + sc_event_subscription_delete_function delete_callback, + sc_bool is_complex_event_subscription, + sc_list * events_list) +{ + sc_unused(ctx); + + if (!sc_storage_is_element(ctx, subscription_addr)) + return null_ptr; + + if (!sc_storage_is_element(ctx, event_type_addr)) + return null_ptr; + + sc_event_subscription * event_subscription = sc_mem_new(sc_event_subscription, 1); + event_subscription->subscription_addr = subscription_addr; + event_subscription->event_type_addr = event_type_addr; + event_subscription->event_element_type = event_element_type; + event_subscription->callback = null_ptr; + event_subscription->callback_with_user = callback; + event_subscription->delete_callback = delete_callback; + event_subscription->data = data; + event_subscription->ref_count = 1; + sc_monitor_init(&event_subscription->monitor); + event_subscription->is_complex_event_subscription = is_complex_event_subscription; + event_subscription->counter_of_activated_events = 0; + if (events_list == null_ptr) + { + event_subscription->max_value_of_activated_events = 0; + event_subscription->events_list = null_ptr; + } + else + { + event_subscription->events_list = events_list; + event_subscription->max_value_of_activated_events = events_list->size; // + } + + event_subscription->execution_counter = 0; + + sc_cond_init(&event_subscription->cond_increase); + sc_cond_init(&event_subscription->cond_decrease); + + // register generated event_subscription + sc_event_subscription_manager * manager = sc_storage_get_event_subscription_manager(); + _sc_event_subscription_manager_add(manager, event_subscription); + + return event_subscription; +} + sc_event_subscription * sc_event_subscription_new( sc_memory_context const * ctx, sc_addr subscription_addr, @@ -225,6 +334,19 @@ sc_result sc_event_subscription_destroy(sc_event_subscription * event_subscripti event_subscription->callback_with_user = null_ptr; event_subscription->delete_callback = null_ptr; event_subscription->data = null_ptr; + sc_cond_destroy(&event_subscription->cond_increase); + sc_cond_destroy(&event_subscription->cond_decrease); + + if (event_subscription->is_complex_event_subscription) + { + if (!sc_list_destroy(event_subscription->events_list)) + return SC_RESULT_ERROR; + event_subscription->is_complex_event_subscription = SC_FALSE; + } + + event_subscription->counter_of_activated_events = 0; + event_subscription->max_value_of_activated_events = 0; + event_subscription->execution_counter = 0; sc_storage * storage = sc_storage_get(); if (storage != null_ptr) @@ -355,11 +477,37 @@ sc_result sc_event_emit_impl( connector_type, other_addr, callback, - event_addr); + event_addr, + ctx, // добавил в функцию параметр + event_type_addr); // добавил в функцию параметр result = SC_RESULT_OK; } + sc_monitor_acquire_write(&event_subscription->monitor); + + if (!sc_event_subscription_is_complex(event_subscription) && event_subscription->events_list != null_ptr) + { + if (++event_subscription->execution_counter == 1) + { + sc_struct_node * list_node = event_subscription->events_list->begin; + + while (list_node != null_ptr && list_node != event_subscription->events_list->end) + { + sc_event_subscription * complex_event_subscription = (sc_event_subscription *)list_node->data; + + if (complex_event_subscription != null_ptr) + { + sc_monitor_acquire_write(&complex_event_subscription->monitor); + sc_cond_broadcast(&complex_event_subscription->cond_increase); + sc_monitor_release_write(&complex_event_subscription->monitor); + } + + list_node = list_node->next; + } + } + } + sc_monitor_release_write(&event_subscription->monitor); element_events_list = element_events_list->next; } sc_monitor_release_read(&subscription_manager->events_table_monitor); @@ -387,3 +535,110 @@ sc_addr sc_event_subscription_get_element(sc_event_subscription const * event_su { return event_subscription->subscription_addr; } + +sc_bool sc_event_subscription_is_complex(sc_event_subscription const * event_subscription) +{ + return event_subscription->is_complex_event_subscription; +} + +sc_result sc_event_subscription_add_complex_events_list( + sc_event_subscription * event_subscription, + sc_list * events_list) +{ + if (event_subscription == null_ptr) + return SC_RESULT_NO; + + if (event_subscription->events_list != null_ptr) //????? type_error with != + sc_list_clear(event_subscription->events_list); + + event_subscription->events_list = events_list; + + return SC_RESULT_OK; +} + +sc_result sc_event_subscription_add_one_complex_event( + sc_event_subscription * complex_event_subscription, + sc_event_subscription const * event_subscription) +{ + if (event_subscription == null_ptr) + return SC_RESULT_NO; + + sc_list_push_back(event_subscription->events_list, complex_event_subscription); + + return SC_RESULT_OK; +} + +sc_bool list_subscription_equal(void * node1, void * node2) +{ ///??? interesting equal function. does it look good? + return node1 == node2; +} + +sc_result sc_event_subscription_delete_one_complex_event( + sc_event_subscription * complex_event_subscription, + sc_event_subscription const * event_subscription) +{ + if (event_subscription == null_ptr) + return SC_RESULT_NO; + + if (event_subscription->events_list == null_ptr) //????? type_error with != + return SC_RESULT_ERROR; + + sc_list_remove_if(event_subscription->events_list, (void *)&complex_event_subscription, list_subscription_equal); + + return SC_RESULT_OK; +} + +gpointer increase_thread(sc_event_subscription * complex_event_subscription) +{ + sc_monitor_acquire_write(&complex_event_subscription->monitor); + while (complex_event_subscription->counter_of_activated_events + < complex_event_subscription->max_value_of_activated_events) + { + sc_cond_wait(&complex_event_subscription->cond_increase, &complex_event_subscription->monitor.rw_mutex); + ++complex_event_subscription->counter_of_activated_events; + } + sc_monitor_release_write(&complex_event_subscription->monitor); + + return null_ptr; +} + +gpointer decrease_thread(sc_event_subscription * complex_event_subscription) +{ + sc_monitor_acquire_write(&complex_event_subscription->monitor); + while (complex_event_subscription->counter_of_activated_events + < complex_event_subscription->max_value_of_activated_events) + { + sc_cond_wait(&complex_event_subscription->cond_decrease, &complex_event_subscription->monitor.rw_mutex); + if (complex_event_subscription->counter_of_activated_events + < complex_event_subscription->max_value_of_activated_events) + break; + --complex_event_subscription->counter_of_activated_events; + } + sc_monitor_release_write(&complex_event_subscription->monitor); + + return null_ptr; +} + +sc_result start_check_condition_to_activate_complex_event( + sc_event_subscription * complex_event_subscription, + sc_memory_context const * ctx, + sc_addr subscription_addr, + sc_event_type event_type_addr, + sc_addr connector_addr, + sc_type connector_type, + sc_addr other_addr, + sc_event_do_after_callback callback, + sc_addr event_addr) +{ + if (complex_event_subscription == null_ptr) + return SC_RESULT_NO; + + sc_thread * t1 = g_thread_new("increase_thread", (GThreadFunc)increase_thread, complex_event_subscription); + sc_thread * t2 = g_thread_new("decrease_thread", (GThreadFunc)decrease_thread, complex_event_subscription); + + g_thread_join(t1); + g_thread_join(t2); + + return sc_event_emit( + ctx, subscription_addr, event_type_addr, connector_addr, connector_type, other_addr, callback, event_addr); +} diff --git a/sc-memory/sc-memory/tests/benchmark/main.cpp b/sc-memory/sc-memory/tests/benchmark/main.cpp index 7ec562987..67e917773 100644 --- a/sc-memory/sc-memory/tests/benchmark/main.cpp +++ b/sc-memory/sc-memory/tests/benchmark/main.cpp @@ -20,6 +20,7 @@ #include "units/template_search_complex.hpp" #include "units/template_search_smoke.hpp" +#include "units/complex_event.hpp" #include #include @@ -545,5 +546,15 @@ BENCHMARK_TEMPLATE(BM_Template, TestScCodeExtended) ->Unit(benchmark::TimeUnit::kMicrosecond) ->Arg(5)->Arg(50)->Arg(500); +BENCHMARK_TEMPLATE(BM_MemoryThreaded, ComplexEventTest) +->Threads(1) +->Iterations(kNodeIters) +->Unit(benchmark::TimeUnit::kMicrosecond); + +BENCHMARK_TEMPLATE(BM_MemoryThreaded, ComplexEventTest) +->Threads(2) +->Iterations(kNodeIters / 2) +->Unit(benchmark::TimeUnit::kMicrosecond); + BENCHMARK_MAIN(); diff --git a/sc-memory/sc-memory/tests/benchmark/units/complex_event.hpp b/sc-memory/sc-memory/tests/benchmark/units/complex_event.hpp new file mode 100644 index 000000000..b6bd1ee28 --- /dev/null +++ b/sc-memory/sc-memory/tests/benchmark/units/complex_event.hpp @@ -0,0 +1,71 @@ +/* +* This source file is part of an OSTIS project. For the latest info, see http://ostis.net +* Distributed under the MIT License +* (See accompanying file COPYING.MIT or copy at http://opensource.org/licenses/MIT) +*/ + +#pragma once + +#include "memory_test.hpp" +#include "sc_event_queue.h" + +#include "sc-core/sc_event_subscription.h" +#include "sc_event_private.h" + +#include "sc-store/sc_storage.h" +#include "sc-store/sc_storage_private.h" +#include "sc_memory_private.h" +#include "sc-core/sc_memory.h" + +#include "sc-core/sc-base/sc_allocator.h" +#include "sc-store/sc-container/sc_struct_node.h" +#include "sc-core/sc_event_subscription.h" + + +class ComplexEventTest : public TestMemory +{ +public: + void Run() + { + ScAddr SubscriptionAddr = m_ctx->CreateNode(ScType::NodeConst); + ScAddr SubscriptionAddr2 = m_ctx->CreateNode(ScType::NodeConst); + ScAddr EventType = m_ctx->CreateNode(ScType::NodeConst); + sc_list * eventsList1 = null_ptr; + sc_list * eventsList2 = null_ptr; + sc_list_init(&eventsList1); + sc_list_init(&eventsList2); + + + sc_event_subscription event1 = sc_complex_event_subscription_new(*m_ctx, SubscriptionAddr, EventType, NULL, NULL, NULL, SC_FALSE, *eventsList1); + sc_event_subscription event2 = sc_complex_event_subscription_new(*m_ctx, SubscriptionAddr2, EventType, NULL, NULL, NULL, SC_FALSE, *eventsList2); + + // Создаем сложное событие, которое сработает только когда оба простых события сработают + sc_event_subscription complexEvent = sc_complex_event_subscription_new(*m_ctx, SubscriptionAddr, EventType, NULL, NULL, NULL, SC_TRUE, NULL); + + + sc_event_subscription_add_one_complex_event(*complexEvent, *event1); + sc_event_subscription_add_one_complex_event(*complexEvent, *event2); + + + ScAddr Connector = m_ctx->CreateNode(ScType::EdgeAccessConstPosPerm); + ScAddr OtherAddr = m_ctx->CreateNode(ScType::NodeConst); + + sc_result complexEventTriggered = start_check_condition_to_activate_complex_event(*complexEvent, *m_ctx, SubscriptionAddr, EventType, + Connector, sc_type_unknown, OtherAddr, NULL, NULL, event1); + + + // Эмитируем первое событие - сложное событие не должно сработать + sc_event_emit(*m_ctx, SubscriptionAddr, EventType, Connector, sc_type_unknown, OtherAddr, NULL, event1); + EXPECT_FALSE(complexEventTriggered == SC_RESULT_OK); + + // Эмитируем второе событие - теперь сложное событие должно сработать + sc_event_emit(*m_ctx, SubscriptionAddr2, EventType, Connector, sc_type_unknown, OtherAddr, NULL, event2); + EXPECT_TRUE(complexEventTriggered == SC_RESULT_OK); + + // Уничтожаем события + sc_event_subscription_destroy(complexEvent); + sc_event_subscription_destroy(event2); + sc_event_subscription_destroy(event1); + } +}; +