diff --git a/src/Tizen.Core/Interop/Interop.Libraries.cs b/src/Tizen.Core/Interop/Interop.Libraries.cs new file mode 100644 index 00000000000..1280560ce0c --- /dev/null +++ b/src/Tizen.Core/Interop/Interop.Libraries.cs @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2024 Samsung Electronics Co., Ltd All Rights Reserved + * + * 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. + */ + +internal static partial class Interop +{ + internal static partial class Libraries + { + public const string TizenCore = "libtizen-core.so.0"; + } +} diff --git a/src/Tizen.Core/Interop/Interop.TizenCore.cs b/src/Tizen.Core/Interop/Interop.TizenCore.cs new file mode 100644 index 00000000000..b3eace0361a --- /dev/null +++ b/src/Tizen.Core/Interop/Interop.TizenCore.cs @@ -0,0 +1,331 @@ +/* + * Copyright (c) 2024 Samsung Electronics Co., Ltd All Rights Reserved + * + * 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. + */ + +using System; +using System.Runtime.InteropServices; + +using Tizen; +using Tizen.Internals.Errors; + +internal static partial class Interop +{ + internal static partial class LibTizenCore + { + internal enum ErrorCode + { + None = Tizen.Internals.Errors.ErrorCode.None, + InvalidParameter = Tizen.Internals.Errors.ErrorCode.InvalidParameter, + OutOfMemory = Tizen.Internals.Errors.ErrorCode.OutOfMemory, + InvalidContext = -0x01100000 | 0x01, + } + + internal enum Priority + { + High = -100, + Default = 0, + HighIdle = 100, + DefaultIdle = 200, + Low = 300, + } + + internal enum PollEvent + { + In = 0x0001, + Pri = 0x0002, + Out = 0x0004, + Err = 0x0008, + Hup = 0x0010, + Nval = 0x0020, + } + + internal static partial class TizenCore + { + // typedef void (*tizen_core_channel_receive_cb)(tizen_core_channel_object_h object, void *user_data); + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + internal delegate void ChannelReceiveCallback(IntPtr channelObject, IntPtr userData); + + // typedef bool (*tizen_core_task_cb)(void *user_data); + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + internal delegate bool TaskCallback(IntPtr userData); + + // typedef bool (*tizen_core_source_prepare_cb)(tizen_core_source_h source, int *timeout, void *user_data); + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + internal delegate bool SourcePrepareCallback(IntPtr source, out int timeout, IntPtr userData); + + // typedef bool (*tizen_core_source_check_cb)(tizen_core_source_h source, void *user_data); + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + internal delegate bool SourceCheckCallback(IntPtr source, IntPtr userData); + + // typedef bool (*tizen_core_source_dispatch_cb)(tizen_core_source_h source, void *user_data); + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + internal delegate bool SourceDispatchCallback(IntPtr source, IntPtr userData); + + // typedef void (*tizen_core_source_finalize_cb)(tizen_core_source_h source, void *user_data); + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + internal delegate void SourceFinalizeCallback(IntPtr source, IntPtr userData); + + // void tizen_core_init(void); + [DllImport(Libraries.TizenCore, EntryPoint = "tizen_core_init")] + internal static extern void Init(); + + // void tizen_core_shutdown(void); + [DllImport(Libraries.TizenCore, EntryPoint = "tizen_core_shutdown")] + internal static extern void Shutdown(); + + // bool tizen_core_ready(void); + [DllImport(Libraries.TizenCore, EntryPoint = "tizen_core_ready")] + internal static extern bool Ready(); + + // int tizen_core_task_create(const char *name, bool use_thread, tizen_core_task_h task); + [DllImport(Libraries.TizenCore, EntryPoint = "tizen_core_task_create")] + internal static extern ErrorCode TaskCreate(string name, bool useThread, out IntPtr handle); + + // int tizen_core_task_destroy(tizen_core_task_h task); + [DllImport(Libraries.TizenCore, EntryPoint = "tizen_core_task_create")] + internal static extern ErrorCode TaskDestroy(IntPtr handle); + + // int tizen_core_task_run(tizen_core_task_h task); + [DllImport(Libraries.TizenCore, EntryPoint = "tizen_core_task_run")] + internal static extern ErrorCode TaskRun(IntPtr handle); + + // int tizen_core_task_is_running(tizen_core_task_h task, bool *running); + [DllImport(Libraries.TizenCore, EntryPoint = "tizen_core_task_is_running")] + internal static extern ErrorCode TaskIsRunning(IntPtr handle, out bool running); + + // int tizen_core_task_quit(tizen_core_task_h task); + [DllImport(Libraries.TizenCore, EntryPoint = "tizen_core_task_quit")] + internal static extern ErrorCode TaskQuit(IntPtr handle); + + // int tizen_core_task_get_tizen_core(tizen_core_task_h task, tizen_core_h *core); + [DllImport(Libraries.TizenCore, EntryPoint = "tizen_core_task_get_tizen_core")] + internal static extern ErrorCode TaskGetTizenCore(IntPtr handle, out IntPtr coreHandle); + + // int tizen_core_find(const char *name, tizen_core_h *core); + [DllImport(Libraries.TizenCore, EntryPoint = "tizen_core_find")] + internal static extern ErrorCode Find(string name, out IntPtr handle); + + // int tizen_core_find_from_this_thread(tizen_core_h *core); + [DllImport(Libraries.TizenCore, EntryPoint = "tizen_core_find_from_this_thread")] + internal static extern ErrorCode FindFromThisThread(out IntPtr handle); + + // int tizen_core_add_idle_job(tizen_core_h core, tizen_core_task_cb callback, void *user_data, tizen_core_source_h *source); + [DllImport(Libraries.TizenCore, EntryPoint = "tizen_core_add_idle_job")] + internal static extern ErrorCode AddIdleJob(IntPtr handle, TaskCallback callback, IntPtr userData, out IntPtr source); + + // int tizen_core_add_timer(tizen_core_h core, unsigned int interval, tizen_core_task_cb callback, void *user_data, tizen_core_source_h *source); + [DllImport(Libraries.TizenCore, EntryPoint = "tizen_core_add_timer")] + internal static extern ErrorCode AddTimer(IntPtr handle, uint interval, TaskCallback callback, IntPtr userData, out IntPtr source); + + // int tizen_core_add_channel(tizen_core_h core, tizen_core_channel_receiver_h receiver, tizen_core_channel_receive_cb callback, void *user_data, tizen_core_source_h *source); + [DllImport(Libraries.TizenCore, EntryPoint = "tizen_core_add_channel")] + internal static extern ErrorCode AddChannel(IntPtr handle, IntPtr channel, ChannelReceiveCallback callback, IntPtr userData, out IntPtr source); + + // int tizen_core_add_event(tizen_core_h core, tizen_core_event_h event, tizen_core_source_h *source); + [DllImport(Libraries.TizenCore, EntryPoint = "tizen_core_add_event")] + internal static extern ErrorCode AddEvent(IntPtr handle, IntPtr eventHandle, out IntPtr source); + + // int tizen_core_emit_event(tizen_core_h core, tizen_core_event_object_h object); + [DllImport(Libraries.TizenCore, EntryPoint = "tizen_core_emit_event")] + internal static extern ErrorCode EmitEvent(IntPtr handle, IntPtr eventObject); + + // int tizen_core_add_source(tizen_core_h core, tizen_core_source_h source); + [DllImport(Libraries.TizenCore, EntryPoint = "tizen_core_add_source")] + internal static extern ErrorCode AddSource(IntPtr handle, IntPtr source); + + // int tizen_core_remove_source(tizen_core_h core, tizen_core_source_h source); + [DllImport(Libraries.TizenCore, EntryPoint = "tizen_core_remove_source")] + internal static extern ErrorCode RemoveSource(IntPtr handle, IntPtr source); + + // int tizen_core_source_create(tizen_core_source_h *source); + [DllImport(Libraries.TizenCore, EntryPoint = "tizen_core_source_create")] + internal static extern ErrorCode SourceCreate(out IntPtr source); + + // int tizen_core_source_destroy(tizen_core_source_h source); + [DllImport(Libraries.TizenCore, EntryPoint = "tizen_core_source_destroy")] + internal static extern ErrorCode SourceDestroy(IntPtr source); + + // int tizen_core_source_add_poll(tizen_core_source_h source, tizen_core_poll_fd_h poll_fd); + [DllImport(Libraries.TizenCore, EntryPoint = "tizen_core_source_add_poll")] + internal static extern ErrorCode SourceAddPoll(IntPtr source, IntPtr pollFd); + + // int tizen_core_source_remove_poll(tizen_core_source_h source, tizen_core_poll_fd_h poll_fd); + [DllImport(Libraries.TizenCore, EntryPoint = "tizen_core_source_remove_poll")] + internal static extern ErrorCode SourceRemovePoll(IntPtr source, IntPtr pollFd); + + // int tizen_core_source_set_prepare_cb(tizen_core_source_h source, tizen_core_source_prepare_cb callback, void *user_data); + [DllImport(Libraries.TizenCore, EntryPoint = "tizen_core_source_set_prepare_cb")] + internal static extern ErrorCode SourceSetPrepareCallback(IntPtr source, SourcePrepareCallback callback, IntPtr userData); + + // int tizen_core_source_set_check_cb(tizen_core_source_h source, tizen_core_source_check_cb callback, void *user_data); + [DllImport(Libraries.TizenCore, EntryPoint = "tizen_core_source_set_check_cb")] + internal static extern ErrorCode SourceSetCheckCallback(IntPtr source, SourceCheckCallback callback, IntPtr userData); + + // int tizen_core_source_set_dispatch_cb(tizen_core_source_h source, tizen_core_source_dispatch_cb callback, void *user_data); + [DllImport(Libraries.TizenCore, EntryPoint = "tizen_core_source_set_dispatch_cb")] + internal static extern ErrorCode SourceSetDispatchCallback(IntPtr source, SourceDispatchCallback callback, IntPtr userData); + + // int tizen_core_source_set_finalize_cb(tizen_core_source_h source, tizen_core_source_finalize_cb callback, void *user_data); + [DllImport(Libraries.TizenCore, EntryPoint = "tizen_core_source_set_finalize_cb")] + internal static extern ErrorCode SourceSetFinalizeCallback(IntPtr source, SourceFinalizeCallback callback, IntPtr userData); + + // int tizen_core_source_set_priority(tizen_core_source_h source, tizen_core_priority_e priority); + [DllImport(Libraries.TizenCore, EntryPoint = "tizen_core_source_set_priority")] + internal static extern ErrorCode SourceSetPriority(IntPtr source, int priority); + + // int tizen_core_poll_fd_create(tizen_core_poll_fd_h *poll_fd); + [DllImport(Libraries.TizenCore, EntryPoint = "tizen_core_poll_fd_create")] + internal static extern ErrorCode PollFdCreate(out IntPtr handle); + + // int tizen_core_poll_fd_destroy(tizen_core_poll_fd_h poll_fd); + [DllImport(Libraries.TizenCore, EntryPoint = "tizen_core_poll_fd_destroy")] + internal static extern ErrorCode PollFdDestroy(IntPtr handle); + + // int tizen_core_poll_fd_set_fd(tizen_core_poll_fd_h poll_fd, int fd); + [DllImport(Libraries.TizenCore, EntryPoint = "tizen_core_poll_fd_set_fd")] + internal static extern ErrorCode PollFdSetFd(IntPtr handle, int fd); + + // int tizen_core_poll_fd_get_fd(tizen_core_poll_fd_h poll_fd, int *fd); + [DllImport(Libraries.TizenCore, EntryPoint = "tizen_core_poll_fd_get_fd")] + internal static extern ErrorCode PollFdGetFd(IntPtr handle, out int fd); + + // int tizen_core_poll_fd_set_events(tizen_core_poll_fd_h poll_fd, uint16_t events); + [DllImport(Libraries.TizenCore, EntryPoint = "tizen_core_poll_fd_set_events")] + internal static extern ErrorCode PollFdSetEvents(IntPtr handle, UInt16 events); + + // int tizen_core_poll_fd_get_events(tizen_core_poll_fd_h poll_fd, uint16_t *events); + [DllImport(Libraries.TizenCore, EntryPoint = "tizen_core_poll_fd_get_events")] + internal static extern ErrorCode PollFdGetEvents(IntPtr handle, out UInt16 events); + + // int tizen_core_poll_fd_set_returned_events(tizen_core_poll_fd_h poll_fd, uint16_t returned_events); + [DllImport(Libraries.TizenCore, EntryPoint = "tizen_core_poll_fd_set_returned_events")] + internal static extern ErrorCode PollFdSetReturnedEvents(IntPtr handle, UInt16 returnedEvents); + + // int tizen_core_poll_fd_get_events(tizen_core_poll_fd_h poll_fd, uint16_t *returned_events); + [DllImport(Libraries.TizenCore, EntryPoint = "tizen_core_poll_fd_get_returned_events")] + internal static extern ErrorCode PollFdGetReturnedEvents(IntPtr handle, out UInt16 returnedEvents); + } + + internal static partial class TizenCoreChannel + { + // int tizen_core_channel_make_pair(tizen_core_channel_sender_h *sender, tizen_core_channel_receiver_h *receiver); + [DllImport(Libraries.TizenCore, EntryPoint = "tizen_core_channel_make_pair")] + internal static extern ErrorCode MakePair(out IntPtr sender, out IntPtr receiver); + + // int tizen_core_channel_sender_send(tizen_core_channel_sender_h sender, tizen_core_channel_object_h object); + [DllImport(Libraries.TizenCore, EntryPoint = "tizen_core_channel_sender_send")] + internal static extern ErrorCode SenderSend(IntPtr sender, IntPtr channelObject); + + // int tizen_core_channel_sender_destroy(tizen_core_channel_sender_h sender); + [DllImport(Libraries.TizenCore, EntryPoint = "tizen_core_channel_sender_destroy")] + internal static extern ErrorCode SenderDestroy(IntPtr sender); + + // int tizen_core_channel_sender_clone(tizen_core_channel_sender_h sender, tizen_core_channel_sender_h *cloned_sender); + [DllImport(Libraries.TizenCore, EntryPoint = "tizen_core_channel_sender_clone")] + internal static extern ErrorCode SenderClone(IntPtr sender, out IntPtr clonedHandle); + + // int tizen_core_channel_receiver_receive(tizen_core_channel_receiver_h receiver, tizen_core_channel_object_h *object); + [DllImport(Libraries.TizenCore, EntryPoint = "tizen_core_channel_receiver_receive")] + internal static extern ErrorCode ReceiverReceive(IntPtr receiver, out IntPtr channelObject); + + // int tizen_core_channel_receiver_destroy(tizen_core_channel_receiver_h receiver); + [DllImport(Libraries.TizenCore, EntryPoint = "tizen_core_channel_receiver_destroy")] + internal static extern ErrorCode ReceiverDestroy(IntPtr receiver); + + // int tizen_core_channel_object_create(tizen_core_channel_object_h *object); + [DllImport(Libraries.TizenCore, EntryPoint = "tizen_core_channel_object_create")] + internal static extern ErrorCode ObjectCreate(out IntPtr handle); + + // int tizen_core_channel_object_destroy(tizen_core_channel_object_h object); + [DllImport(Libraries.TizenCore, EntryPoint = "tizen_core_channel_object_destroy")] + internal static extern ErrorCode ObjectDestroy(IntPtr handle); + + // int tizen_core_channel_object_set_id(tizen_core_channel_object_h object, int id); + [DllImport(Libraries.TizenCore, EntryPoint = "tizen_core_channel_object_set_id")] + internal static extern ErrorCode ObjectSetId(IntPtr handle, int id); + + // int tizen_core_channel_object_get_id(tizen_core_channel_object_h object, int *id); + [DllImport(Libraries.TizenCore, EntryPoint = "tizen_core_channel_object_get_id")] + internal static extern ErrorCode ObjectGetId(IntPtr handle, out int id); + + // int tizen_core_channel_object_set_data(tizen_core_channel_object_h object, void *data); + [DllImport(Libraries.TizenCore, EntryPoint = "tizen_core_channel_object_set_data")] + internal static extern ErrorCode ObjectSetData(IntPtr handle, IntPtr data); + + // int tizen_core_channel_object_get_data(tizen_core_channel_object_h object, void **data); + [DllImport(Libraries.TizenCore, EntryPoint = "tizen_core_channel_object_get_data")] + internal static extern ErrorCode ObjectGetData(IntPtr handle, out IntPtr data); + + // int tizen_core_channel_object_get_sender_task_name(tizen_core_channel_object_h object, const char **task_name); + [DllImport(Libraries.TizenCore, EntryPoint = "tizen_core_channel_object_get_sender_task_name")] + internal static extern ErrorCode ObjectGetSenderTaskName(IntPtr handle, out IntPtr taskName); + } + + internal static partial class TizenCoreEvent + { + // typedef bool (*tizen_core_event_handler_cb)(tizen_core_event_object_h object, void *user_data); + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + internal delegate bool EventHandlerCallback(IntPtr eventObject, IntPtr userData); + + // typedef void (*tizen_core_event_object_destroy_cb)(void *event_data, void *user_data); + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + internal delegate void EventObjectDestroyCallback(IntPtr eventData, IntPtr userData); + + // int tizen_core_event_create(tizen_core_event_h *event); + [DllImport(Libraries.TizenCore, EntryPoint = "tizen_core_event_create")] + internal static extern ErrorCode Create(out IntPtr handle); + + // int tizen_core_event_destroy(tizen_core_event_h event); + [DllImport(Libraries.TizenCore, EntryPoint = "tizen_core_event_destroy")] + internal static extern ErrorCode Destroy(IntPtr handle); + + // int tizen_core_event_add_handler(tizen_core_event_h event, tizen_core_event_handler_cb handler, void *user_data, tizen_core_event_handler_h *event_handler); + [DllImport(Libraries.TizenCore, EntryPoint = "tizen_core_event_add_handler")] + internal static extern ErrorCode AddHandler(IntPtr handle, EventHandlerCallback callback, IntPtr userData, out IntPtr eventHandler); + + // int tizen_core_event_prepend_handler(tizen_core_event_h event, tizen_core_event_handler_cb handler, void *user_data, tizen_core_event_handler_h *event_handler); + [DllImport(Libraries.TizenCore, EntryPoint = "tizen_core_event_prepend_handler")] + internal static extern ErrorCode PrependHandler(IntPtr handle, EventHandlerCallback callback, IntPtr userData, out IntPtr eventHandler); + + // int tizen_core_event_remove_handler(tizen_core_event_h event, tizen_core_event_handler_h event_handler); + [DllImport(Libraries.TizenCore, EntryPoint = "tizen_core_event_remove_handler")] + internal static extern ErrorCode RemoveHandler(IntPtr handle, IntPtr eventHandler); + + // int tizen_core_event_emit(tizen_core_event_h event, tizen_core_event_object_h object); + [DllImport(Libraries.TizenCore, EntryPoint = "tizen_core_event_emit")] + internal static extern ErrorCode Emit(IntPtr handle, IntPtr eventObject); + + // int tizen_core_event_object_create(tizen_core_event_object_h *object, int id, void *data); + [DllImport(Libraries.TizenCore, EntryPoint = "tizen_core_event_object_create")] + internal static extern ErrorCode ObjectCreate(out IntPtr handle, int id, IntPtr data); + + // int tizen_core_event_object_destroy(tizen_core_event_object_h object); + [DllImport(Libraries.TizenCore, EntryPoint = "tizen_core_event_object_destroy")] + internal static extern ErrorCode ObjectDestroy(IntPtr handle); + + // int tizen_core_event_object_set_destroy_cb(tizen_core_event_object_h object, tizen_core_event_object_destroy_cb callback, void *user_data); + [DllImport(Libraries.TizenCore, EntryPoint = "tizen_core_event_object_set_destroy_cb")] + internal static extern ErrorCode ObjectSetDestroyCallback(IntPtr handle, EventObjectDestroyCallback callback, IntPtr userData); + + // int tizen_core_event_object_get_id(tizen_core_event_object_h object, int *id); + [DllImport(Libraries.TizenCore, EntryPoint = "tizen_core_event_object_get_id")] + internal static extern ErrorCode ObjectGetId(IntPtr handle, out int id); + + // int tizen_core_event_object_get_data(tizen_core_event_object_h object, void *data); + [DllImport(Libraries.TizenCore, EntryPoint = "tizen_core_event_object_get_data")] + internal static extern ErrorCode ObjectGetData(IntPtr handle, out IntPtr data); + } + } +} diff --git a/src/Tizen.Core/Tizen.Core.csproj b/src/Tizen.Core/Tizen.Core.csproj new file mode 100644 index 00000000000..37f8af30eec --- /dev/null +++ b/src/Tizen.Core/Tizen.Core.csproj @@ -0,0 +1,12 @@ + + + + net6.0 + + + + + + + + diff --git a/src/Tizen.Core/Tizen.Core.sln b/src/Tizen.Core/Tizen.Core.sln new file mode 100644 index 00000000000..7dd607db6ab --- /dev/null +++ b/src/Tizen.Core/Tizen.Core.sln @@ -0,0 +1,37 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.0.31903.59 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tizen.Core", "Tizen.Core.csproj", "{1BA08908-7B2B-42D1-A124-092CB177BF4C}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tizen", "..\Tizen\Tizen.csproj", "{2E04FB0F-03F4-40B0-BB25-5ADFB08C8DF3}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tizen.Log", "..\Tizen.Log\Tizen.Log.csproj", "{8DA5B43B-63E9-460C-B64F-0B691539DC5D}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {1BA08908-7B2B-42D1-A124-092CB177BF4C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {1BA08908-7B2B-42D1-A124-092CB177BF4C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1BA08908-7B2B-42D1-A124-092CB177BF4C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {1BA08908-7B2B-42D1-A124-092CB177BF4C}.Release|Any CPU.Build.0 = Release|Any CPU + {2E04FB0F-03F4-40B0-BB25-5ADFB08C8DF3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {2E04FB0F-03F4-40B0-BB25-5ADFB08C8DF3}.Debug|Any CPU.Build.0 = Debug|Any CPU + {2E04FB0F-03F4-40B0-BB25-5ADFB08C8DF3}.Release|Any CPU.ActiveCfg = Release|Any CPU + {2E04FB0F-03F4-40B0-BB25-5ADFB08C8DF3}.Release|Any CPU.Build.0 = Release|Any CPU + {8DA5B43B-63E9-460C-B64F-0B691539DC5D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {8DA5B43B-63E9-460C-B64F-0B691539DC5D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {8DA5B43B-63E9-460C-B64F-0B691539DC5D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {8DA5B43B-63E9-460C-B64F-0B691539DC5D}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {E9B5E719-0EB7-430C-97DC-3FE2E50EE668} + EndGlobalSection +EndGlobal \ No newline at end of file diff --git a/src/Tizen.Core/Tizen.Core/Channel.cs b/src/Tizen.Core/Tizen.Core/Channel.cs new file mode 100644 index 00000000000..402710595c5 --- /dev/null +++ b/src/Tizen.Core/Tizen.Core/Channel.cs @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2024 Samsung Electronics Co., Ltd All Rights Reserved + * + * 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. + */ + +using System; + +namespace Tizen.Core +{ + /// + /// The class for managing communication channels between tasks of Tizen Core. + /// + /// 12 + public class Channel : IDisposable + { + private bool _disposed = false; + + /// + /// Constructor for creating a new channel with a sender and a receiver. + /// + /// Thrown when out of memory. + /// + /// + /// + /// try + /// { + /// var channel = new Channel(); + /// } + /// catch (OutOfMemoryException) + /// { + /// Console.WriteLine("Exception occurs"); + /// } + /// + /// + /// + /// 12 + public Channel() + { + Interop.LibTizenCore.ErrorCode error = Interop.LibTizenCore.TizenCoreChannel.MakePair(out IntPtr sender, out IntPtr receiver); + TCoreErrorFactory.CheckAndThrownException(error, "Failed to make a channel pair"); + Sender = new ChannelSender(sender); + Receiver = new ChannelReceiver(receiver); + } + + /// + /// Finalizer of the class Channel. + /// + ~Channel() + { + Dispose(false); + } + + /// + /// Gets the channel sender instance. + /// + /// 12 + public ChannelSender Sender { get; private set; } + + /// + /// Gets the channel receiver instance. + /// + /// 12 + public ChannelReceiver Receiver { get; private set; } + + /// + /// Release any unmanaged resources used by this object. + /// + /// If true, disposes any disposable objects. If false, does not dispose disposable objects. + /// 12 + protected virtual void Dispose(bool disposing) + { + if (!_disposed) + { + if (disposing) + { + Sender.Dispose(); + Receiver.Dispose(); + } + + _disposed = true; + } + } + + /// + /// Release any unmanaged resources used by this object. + /// + /// 12 + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + } +} diff --git a/src/Tizen.Core/Tizen.Core/ChannelObject.cs b/src/Tizen.Core/Tizen.Core/ChannelObject.cs new file mode 100644 index 00000000000..64a35b975af --- /dev/null +++ b/src/Tizen.Core/Tizen.Core/ChannelObject.cs @@ -0,0 +1,174 @@ +/* + * Copyright (c) 2024 Samsung Electronics Co., Ltd All Rights Reserved + * + * 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. + */ + +using System; +using System.Collections.Concurrent; +using System.Runtime.InteropServices; + +namespace Tizen.Core +{ + /// + /// Represents a channel object used for inter-task communication. + /// + /// 12 + public class ChannelObject : IDisposable + { + private IntPtr _handle = IntPtr.Zero; + private bool _disposed = false; + private static readonly ConcurrentDictionary _dataMap = new ConcurrentDictionary(); + private static readonly object _dataLock = new object(); + private static int _dataId = 0; + + /// + /// Constructor for creating a new channel object with specified ID and data. + /// + /// The ID. + /// The data object. + /// Thrown when out of memory. + /// + /// + /// + /// int id = 0; + /// string message = "Test message"; + /// var channelObject = new ChannelObject(id++, message); + /// + /// + /// + /// 12 + public ChannelObject(int id, object data) + { + Interop.LibTizenCore.ErrorCode error = Interop.LibTizenCore.TizenCoreChannel.ObjectCreate(out _handle); + TCoreErrorFactory.CheckAndThrownException(error, "Failed to create channel object"); + Id = id; + Data = data; + IsUsed = false; + } + + internal ChannelObject(IntPtr handle) + { + _handle = handle; + IsUsed = false; + } + + /// + /// Finalizer of the class ChannelObject. + /// + ~ChannelObject() + { + Dispose(false); + } + + /// + /// Gets and sets the ID. + /// + /// 12 + public int Id + { + get + { + Interop.LibTizenCore.TizenCoreChannel.ObjectGetId(_handle, out int id); + return id; + } + set + { + Interop.LibTizenCore.TizenCoreChannel.ObjectSetId(_handle, value); + } + } + + /// + /// Gets and sets the data object. + /// + /// 12 + public object Data + { + get + { + Interop.LibTizenCore.TizenCoreChannel.ObjectGetData(_handle, out IntPtr handle); + int id = (int)handle; + if (_dataMap.TryGetValue(id, out var data)) + { + return data; + } + return null; + } + set + { + int id; + lock (_dataLock) + { + id = _dataId++; + } + _dataMap[id] = value; + Interop.LibTizenCore.TizenCoreChannel.ObjectSetData(_handle, (IntPtr)id); + } + } + + /// + /// Gets the name of the sender task. + /// + /// 12 + public string Sender { + get + { + Interop.LibTizenCore.TizenCoreChannel.ObjectGetSenderTaskName(_handle, out IntPtr taskName); + return Marshal.PtrToStringAnsi(taskName); + } + } + + internal bool IsUsed { set; get; } + + internal IntPtr Handle { get { return _handle; } } + + /// + /// Release any unmanaged resources used by this object. + /// + /// If true, disposes any disposable objects. If false, does not dispose disposable objects. + /// 12 + protected virtual void Dispose(bool disposing) + { + if (!_disposed) + { + if (disposing) + { + if (_handle != IntPtr.Zero) + { + if (!IsUsed) + { + Interop.LibTizenCore.TizenCoreChannel.ObjectGetData(_handle, out IntPtr handle); + int id = (int)handle; + _dataMap.TryRemove(id, out var data); + } + + Interop.LibTizenCore.TizenCoreChannel.ObjectDestroy(_handle); + _handle = IntPtr.Zero; + } + } + + _disposed = true; + } + } + + /// + /// Release any unmanaged resources used by this object. + /// + /// 12 + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + } +} diff --git a/src/Tizen.Core/Tizen.Core/ChannelReceivedEventArgs.cs b/src/Tizen.Core/Tizen.Core/ChannelReceivedEventArgs.cs new file mode 100644 index 00000000000..4c5fdf13eb4 --- /dev/null +++ b/src/Tizen.Core/Tizen.Core/ChannelReceivedEventArgs.cs @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2024 Samsung Electronics Co., Ltd All Rights Reserved + * + * 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. + */ + +using System; + +namespace Tizen.Core +{ + /// + /// Arguments for the event raised when an object has been received through a channel. + /// + /// 12 + public class ChannelReceivedEventArgs : System.EventArgs + { + internal ChannelReceivedEventArgs(ChannelObject channelObject) + { + if (channelObject == null) + { + throw new ArgumentNullException(nameof(channelObject)); + } + + Id = channelObject.Id; + Data = channelObject.Data; + Sender = channelObject.Sender; + } + + /// + /// Gets the ID of the received object. + /// + /// 12 + public int Id { get; private set; } + + /// + /// Gets the Data of the received object. + /// + /// 12 + public object Data { get; private set; } + + /// + /// Gets the name of the sender task of the received object. + /// + /// 12 + public string Sender { get; private set; } + } +} \ No newline at end of file diff --git a/src/Tizen.Core/Tizen.Core/ChannelReceiver.cs b/src/Tizen.Core/Tizen.Core/ChannelReceiver.cs new file mode 100644 index 00000000000..c8169954131 --- /dev/null +++ b/src/Tizen.Core/Tizen.Core/ChannelReceiver.cs @@ -0,0 +1,133 @@ +/* + * Copyright (c) 2024 Samsung Electronics Co., Ltd All Rights Reserved + * + * 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. + */ + +using System; +using System.Threading.Tasks; + +namespace Tizen.Core +{ + /// + /// Represents the channel receiver used for inter-task communication. + /// + /// 12 + public class ChannelReceiver : IDisposable + { + private bool _disposed = false; + + internal ChannelReceiver(IntPtr handle) + { + Handle = handle; + Source = IntPtr.Zero; + Id = 0; + } + + /// + /// Finalizer of the class ChannelReceiver. + /// + ~ChannelReceiver() + { + Dispose(false); + } + + /// + /// Occurrs whenever the channel object is received in the main loop of the task. + /// + /// + /// The registered event handler will be invoked when the channel receiver is added to the specific task. + /// + /// + /// + /// + /// var channel = new Channel(); + /// var receiver = channel.Receiver; + /// receiver.Received += (s, e) => { + /// Console.WriteLine("OnChannelObjectReceived. Message = {}", (string)e.Data); + /// }; + /// + /// + /// + /// 12 + public event EventHandler Received; + + /// + /// Receives the channel object from the sender asynchronously. + /// + /// The received channel object. + /// + /// + /// + /// var channel = new Channel(); + /// var task = TizenCore.Find("Test"); + /// task.Send(async () => { + /// var channelObject = await channel.Receiver.Receive(); + /// Console.WriteLine("Message = {}", (string)channelObject.Data); + /// }); + /// + /// + /// + /// 12 + public async Task Receive() + { + return await System.Threading.Tasks.Task.Run(() => + { + Interop.LibTizenCore.ErrorCode error = Interop.LibTizenCore.TizenCoreChannel.ReceiverReceive(Handle, out IntPtr channelObject); + TCoreErrorFactory.CheckAndThrownException(error, "Failed to receive channel object"); + return new ChannelObject(channelObject); + }).ConfigureAwait(false); + } + + internal IntPtr Handle { get; set; } + internal IntPtr Source { get; set; } + internal int Id { get; set; } + + internal void InvokeEventHandler(object sender, ChannelReceivedEventArgs e) + { + Received?.Invoke(sender, e); + } + + /// + /// Release any unmanaged resources used by this object. + /// + /// If true, disposes any disposable objects. If false, does not dispose disposable objects. + /// 12 + protected virtual void Dispose(bool disposing) + { + if (!_disposed) + { + if (disposing) + { + if (Handle != IntPtr.Zero) + { + Interop.LibTizenCore.TizenCoreChannel.ReceiverDestroy(Handle); + Handle = IntPtr.Zero; + } + } + + _disposed = true; + } + } + + /// + /// Release any unmanaged resources used by this object. + /// + /// 12 + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + } +} diff --git a/src/Tizen.Core/Tizen.Core/ChannelSender.cs b/src/Tizen.Core/Tizen.Core/ChannelSender.cs new file mode 100644 index 00000000000..45be966a802 --- /dev/null +++ b/src/Tizen.Core/Tizen.Core/ChannelSender.cs @@ -0,0 +1,134 @@ +/* + * Copyright (c) 2024 Samsung Electronics Co., Ltd All Rights Reserved + * + * 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. + */ + +using System; + +namespace Tizen.Core +{ + /// + /// Represents the channel sender used for inter-task communication. + /// + /// 12 + public class ChannelSender : IDisposable + { + private bool _disposed = false; + + internal ChannelSender(IntPtr handle) + { + Handle = handle; + } + + /// + /// Finalizer of the class ChannelSender. + /// + ~ChannelSender() + { + Dispose(false); + } + + /// + /// Sends the channel object to the receiver. + /// + /// The channel object instance. + /// Thrown when the argument is null. + /// + /// It's important to call the Dispose() method on the passed channel object to release resources. + /// + /// + /// + /// + /// var channel = new Channel(); + /// var sender = channel.Sender; + /// string message = "Test"; + /// using (var channelObject = new ChannelObject(1, message)) + /// { + /// sender.Send(channelObject); + /// } + /// + /// + /// + /// 12 + public void Send(ChannelObject channelObject) + { + if (channelObject == null) + { + throw new ArgumentNullException(nameof(channelObject)); + } + + Interop.LibTizenCore.ErrorCode error = Interop.LibTizenCore.TizenCoreChannel.SenderSend(Handle, channelObject.Handle); + TCoreErrorFactory.CheckAndThrownException(error, "Failed to send channel object"); + channelObject.IsUsed = true; + } + + /// + /// Creates and returns a copy of the channel sender object. + /// + /// A newly created channel sender instance. + /// Thrown when the argument is invalid. + /// Thrown when out of memory. + /// + /// + /// + /// var channel = new Channel(); + /// var sender = channel.Sender; + /// var clonedSender = sender.Clone(); + /// + /// + /// + /// 12 + public ChannelSender Clone() + { + Interop.LibTizenCore.ErrorCode error = Interop.LibTizenCore.TizenCoreChannel.SenderClone(Handle, out IntPtr clonedHandle); + TCoreErrorFactory.CheckAndThrownException(error, "Failed to clone channel sender"); + + return new ChannelSender(clonedHandle); + } + + internal IntPtr Handle { get; private set; } + + /// + /// Release any unmanaged resources used by this object. + /// + /// If true, disposes any disposable objects. If false, does not dispose disposable objects. + /// 12 + protected virtual void Dispose(bool disposing) + { + if (!_disposed) + { + if (disposing) + { + if (Handle != IntPtr.Zero) + { + Interop.LibTizenCore.TizenCoreChannel.SenderDestroy(Handle); + Handle = IntPtr.Zero; + } + } + + _disposed = true; + } + } + + /// + /// Release any unmanaged resources used by this object. + /// + /// 12 + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + } +} diff --git a/src/Tizen.Core/Tizen.Core/Event.cs b/src/Tizen.Core/Tizen.Core/Event.cs new file mode 100644 index 00000000000..d9fc25b184b --- /dev/null +++ b/src/Tizen.Core/Tizen.Core/Event.cs @@ -0,0 +1,173 @@ +/* + * Copyright (c) 2024 Samsung Electronics Co., Ltd All Rights Reserved + * + * 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. + */ + +using System; + +namespace Tizen.Core +{ + /// + /// Represents the event using for broadcasting events. + /// + /// 12 +#pragma warning disable CA1716 + public class Event : IDisposable +#pragma warning restore CA1716 + { + private IntPtr _handle = IntPtr.Zero; + private bool _disposed = false; + private Interop.LibTizenCore.TizenCoreEvent.EventHandlerCallback _callback = null; + + /// + /// Constructor for creating a new event instance. + /// + /// Thrown when out of memory. + /// + /// + /// + /// var coreEvent = new Event(); + /// + /// + /// + /// 12 + public Event() + { + Interop.LibTizenCore.ErrorCode error = Interop.LibTizenCore.TizenCoreEvent.Create(out _handle); + TCoreErrorFactory.CheckAndThrownException(error, "Failed to create event"); + + _callback = new Interop.LibTizenCore.TizenCoreEvent.EventHandlerCallback(EventHandlerCallback); + error = Interop.LibTizenCore.TizenCoreEvent.AddHandler(_handle, _callback, IntPtr.Zero, out IntPtr _); + TCoreErrorFactory.CheckAndThrownException(error, "Failed to add event handler"); + + Source = IntPtr.Zero; + Id = 0; + } + + /// + /// Finalizer of the class Event. + /// + ~Event() + { + Dispose(false); + } + + private bool EventHandlerCallback(IntPtr eventData, IntPtr userData) + { + using (var eventObject = new EventObject(eventData)) + { + EventReceived?.Invoke(this, new EventReceivedEventArgs(eventObject)); + } + return true; + } + + /// + /// Occurrs whenever the event is received in the main loop of the task. + /// + /// + /// The registered event handler will be invoked when the event is added to the specific task. + /// + /// + /// + /// + /// var coreEvent = new Event(); + /// coreEvent.EventReceived += (s, e) => { + /// Console.WriteLine("OnEventReceived. Message = {}", (string)e.Data); + /// }; + /// + /// + /// + /// 12 + public event EventHandler EventReceived; + + /// + /// Emits an event object to the event. + /// The emitted event object is queued and delivered to the registered EventHandlers on the main loop of the task. + /// + /// The event object instance. + /// Thrown when the argument is null. + /// + /// If the event is not added to the task, the emitted event object will be pended until the event is added to the task. + /// + /// + /// + /// + /// var coreEvent = new Event(); + /// coreEvent.EventReceived += (s, e) => { + /// Console.WriteLine("OnEventReceived. Message = {}", (string)e.Data); + /// }; + /// + /// var task = TizenCore.Find("EventTask"); + /// if (task != null) + /// { + /// task.AddEvent(coreEvent); + /// string message = "Test Event"; + /// using (var eventObject = new EventObject(1, message)) + /// { + /// coreEvent.Emit(eventObject); + /// } + /// } + /// + /// + /// + /// 12 + public void Emit(EventObject eventObject) + { + if (eventObject == null) + { + throw new ArgumentNullException(nameof(eventObject)); + } + + Interop.LibTizenCore.ErrorCode error = Interop.LibTizenCore.TizenCoreEvent.Emit(_handle, eventObject.Handle); + TCoreErrorFactory.CheckAndThrownException(error, "Failed to emit event object"); + eventObject.Handle = IntPtr.Zero; + } + + internal IntPtr Handle { get { return _handle; } set { _handle = value; } } + internal IntPtr Source { get; set; } + internal int Id { get; set; } + + /// + /// Release any unmanaged resources used by this object. + /// + /// If true, disposes any disposable objects. If false, does not dispose disposable objects. + /// 12 + protected virtual void Dispose(bool disposing) + { + if (!_disposed) + { + if (disposing) + { + if (_handle != IntPtr.Zero) + { + Interop.LibTizenCore.TizenCoreEvent.Destroy(_handle); + _handle = IntPtr.Zero; + } + } + + _disposed = true; + } + } + + /// + /// Release any unmanaged resources used by this object. + /// + /// 12 + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + } +} diff --git a/src/Tizen.Core/Tizen.Core/EventObject.cs b/src/Tizen.Core/Tizen.Core/EventObject.cs new file mode 100644 index 00000000000..804a7e08a30 --- /dev/null +++ b/src/Tizen.Core/Tizen.Core/EventObject.cs @@ -0,0 +1,148 @@ +/* + * Copyright (c) 2024 Samsung Electronics Co., Ltd All Rights Reserved + * + * 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. + */ + +using System; +using System.Collections.Concurrent; + +namespace Tizen.Core +{ + /// + /// Represents an event object used for broadcasting the event. + /// + /// 12 + public class EventObject : IDisposable + { + private IntPtr _handle = IntPtr.Zero; + private bool _disposed = false; + private static readonly ConcurrentDictionary _dataMap = new ConcurrentDictionary(); + private static readonly object _dataLock = new object(); + private static int _dataId = 0; + private static Interop.LibTizenCore.TizenCoreEvent.EventObjectDestroyCallback _destroyCallback = new Interop.LibTizenCore.TizenCoreEvent.EventObjectDestroyCallback(NativeObjectDestroyCallback); + + /// + /// Constructor for creating a new event object with specified ID and data. + /// + /// The ID. + /// The data object. + /// Thrown when out of memory. + /// + /// + /// + /// int id = 0; + /// string message = "Test event"; + /// var eventObject = new EventObject(id++, message); + /// + /// + /// + /// 12 + public EventObject(int id, object data) + { + int dataId; + lock (_dataLock) + { + dataId = _dataId++; + } + + _dataMap[dataId] = data; + Interop.LibTizenCore.ErrorCode error = Interop.LibTizenCore.TizenCoreEvent.ObjectCreate(out _handle, id, (IntPtr)dataId); + TCoreErrorFactory.CheckAndThrownException(error, "Failed to create channel object"); + + Interop.LibTizenCore.TizenCoreEvent.ObjectSetDestroyCallback(_handle, _destroyCallback, (IntPtr)dataId); + } + + internal EventObject(IntPtr handle) + { + _handle = handle; + } + + /// + /// Finalizer of the class EventObject. + /// + ~EventObject() + { + Dispose(false); + } + + /// + /// Gets the ID of the event object. + /// + public int Id + { + get + { + Interop.LibTizenCore.TizenCoreEvent.ObjectGetId(_handle, out int id); + return id; + } + } + + /// + /// Gets the Data of the event object. + /// + public object Data + { + get + { + Interop.LibTizenCore.TizenCoreEvent.ObjectGetData(_handle, out IntPtr handle); + int id = (int)handle; + if (_dataMap.TryGetValue(id, out var data)) + { + return data; + } + return null; + } + } + + internal IntPtr Handle { get { return _handle; } set { _handle = value; } } + + /// + /// Release any unmanaged resources used by this object. + /// + /// If true, disposes any disposable objects. If false, does not dispose disposable objects. + /// 12 + protected virtual void Dispose(bool disposing) + { + if (!_disposed) + { + if (disposing) + { + if (_handle != IntPtr.Zero) + { + Interop.LibTizenCore.TizenCoreEvent.ObjectDestroy(_handle); + _handle = IntPtr.Zero; + } + } + + _disposed = true; + } + } + + /// + /// Release any unmanaged resources used by this object. + /// + /// 12 + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + private static void NativeObjectDestroyCallback(IntPtr eventData, IntPtr userData) + { + int dataId = (int)eventData; + _dataMap.TryRemove(dataId, out var _); + } + } +} diff --git a/src/Tizen.Core/Tizen.Core/EventReceivedEventArgs.cs b/src/Tizen.Core/Tizen.Core/EventReceivedEventArgs.cs new file mode 100644 index 00000000000..fb561bbd686 --- /dev/null +++ b/src/Tizen.Core/Tizen.Core/EventReceivedEventArgs.cs @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2024 Samsung Electronics Co., Ltd All Rights Reserved + * + * 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. + */ + +using System; + +namespace Tizen.Core +{ + /// + /// Arguments for the event raised when the event data is received. + /// + /// 12 + public class EventReceivedEventArgs : System.EventArgs + { + internal EventReceivedEventArgs(EventObject eventObject) + { + if (eventObject == null) + { + throw new ArgumentNullException(nameof(eventObject)); + } + + Id = eventObject.Id; + Data = eventObject.Data; + } + + /// + /// Gets the ID of the received object. + /// + /// 12 + public int Id { get; private set; } + + /// + /// Gets the Data of the received object. + /// + /// 12 + public object Data { get; private set; } + } +} diff --git a/src/Tizen.Core/Tizen.Core/Log.cs b/src/Tizen.Core/Tizen.Core/Log.cs new file mode 100644 index 00000000000..17d57a62df2 --- /dev/null +++ b/src/Tizen.Core/Tizen.Core/Log.cs @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2024 Samsung Electronics Co., Ltd All Rights Reserved + * + * 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. + */ + +using System.Runtime.CompilerServices; + +namespace Tizen.Core +{ + internal class Log + { + private static string LogTag = "Tizen.Core"; + + public static void Error(string message, [CallerFilePath] string file = "", [CallerMemberName] string func = "", [CallerLineNumber] int line = 0) + { + Tizen.Log.Error(LogTag, message, file, func, line); + } + + public static void Warn(string message, [CallerFilePath] string file = "", [CallerMemberName] string func = "", [CallerLineNumber] int line = 0) + { + Tizen.Log.Warn(LogTag, message, file, func, line); + } + + public static void Info(string message, [CallerFilePath] string file = "", [CallerMemberName] string func = "", [CallerLineNumber] int line = 0) + { + Tizen.Log.Info(LogTag, message, file, func, line); + } + + public static void Debug(string message, [CallerFilePath] string file = "", [CallerMemberName] string func = "", [CallerLineNumber] int line = 0) + { + Tizen.Log.Debug(LogTag, message, file, func, line); + } + } +} \ No newline at end of file diff --git a/src/Tizen.Core/Tizen.Core/Task.cs b/src/Tizen.Core/Tizen.Core/Task.cs new file mode 100644 index 00000000000..1e8b52299ae --- /dev/null +++ b/src/Tizen.Core/Tizen.Core/Task.cs @@ -0,0 +1,717 @@ +/* + * Copyright (c) 2024 Samsung Electronics Co., Ltd All Rights Reserved + * + * 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. + */ + +using System; +using System.Collections.Concurrent; +using System.Diagnostics.Tracing; +using System.Threading.Channels; +using System.Threading.Tasks; + +namespace Tizen.Core +{ + /// + /// Represents the task used for creating, running and terminating the thread with the main loop. + /// The state of the task can be changed as follows: Constructed -> Running -> Terminated. + /// To start the task, use 'Task.Run()' method. Once started, the task enters into 'Running' state. To terminate the task, use 'Task.Quit()' method. + /// After termination, the task returns back to 'Constructed' state. + /// + /// 12 + public class Task : IDisposable + { + private IntPtr _handle = IntPtr.Zero; + private bool _disposed = false; + private static readonly ConcurrentDictionary _coreTaskMap = new ConcurrentDictionary(); + private static readonly ConcurrentDictionary> _taskMap = new ConcurrentDictionary>(); + private static readonly ConcurrentDictionary _actionkMap = new ConcurrentDictionary(); + private static readonly ConcurrentDictionary _timerMap = new ConcurrentDictionary(); + private static readonly ConcurrentDictionary _channelMap = new ConcurrentDictionary(); + private static readonly ConcurrentDictionary _eventMap = new ConcurrentDictionary(); + private static Object _idLock = new Object(); + private static int _id = 1; + + /// + /// Initializes the Task class. + /// + /// The ID of the task. + /// Thrown when the is invalid or a Task with that ID already exists. + /// Thrown when out of memory. + /// + /// The constructor throws an exception when the id already exists. + /// By default, the task creates a thread. However, if the is "main", a thread is not created. + /// The 'main' task will be operated in the main thread. + /// + /// + /// + /// + /// TizenCore.Initialize(); + /// var task = new Task("Worker"); + /// task.Run(); + /// + /// + /// + /// 12 + public Task(string id) + { + bool useThread = (id == "main") ? false : true; + Interop.LibTizenCore.ErrorCode error = Interop.LibTizenCore.TizenCore.TaskCreate(id, useThread, out _handle); + TCoreErrorFactory.CheckAndThrownException(error, "Failed to create task"); + _coreTaskMap[id] = this; + } + + internal Task(IntPtr handle) + { + _handle = handle; + _disposed = true; + } + + /// + /// Finalizes the Task class. + /// + /// 12 + ~Task() + { + Dispose(false); + } + + + /// + /// Posts an action to be executed later. + /// + /// The action callback to post. + /// Thrown when the action argument is null. + /// Thrown when failed because of the instance is invalid. + /// Thrown when out of memory. + /// + /// The action callback will be executed by the main loop of the task. + /// If there was any error during this process, an appropriate exception will be thrown. + /// In order to prevent the from throwing an exception, you should add a try/catch block. If not, it may cause the application to crash or terminate. + /// + /// + /// + /// + /// var task = TizenCore.Find("Test") ?? TizenCore.Spawn("Test"); + /// task.Post(() => + /// { + /// Console.WriteLine("Test task"); + /// }); + /// + /// + /// + /// 12 + public void Post(Action action) + { + if (action == null) + { + throw new ArgumentNullException(nameof(action)); + } + + int id; + lock (_idLock) + { + if (_id + 1 < 0) _id = 1; + id = _id++; + } + _actionkMap[id] = action; + Interop.LibTizenCore.ErrorCode error = Interop.LibTizenCore.TizenCore.AddIdleJob(_handle, NativeActionCallback, (IntPtr)id, out IntPtr handle); + TCoreErrorFactory.CheckAndThrownException(error, "Failed to add idle job"); + } + + /// + /// Posts a task to be executed later. + /// + /// The task to post. + /// Thrown when the task argument is null. + /// Thrown when failed because of the instance is invalid. + /// Thrown when out of memory. + /// + /// The task will be stored in the internal map using its unique identifier. + /// Then it will be added as an idle job to the main loop of the task. + /// If there was any error during this process, the task will be removed from the map and an appropriate exception will be thrown. + /// In order to prevent the from throwing an exception, you should add a try/catch block. If not, it may cause the application to crash or terminate. + /// + /// + /// + /// + /// var channel = new Channel(); + /// var task = TizenCore.Find("Sender") ?? TizenCore.Spawn("Sender"); + /// + /// int id = 0; + /// task.Post(async () => + /// { + /// var channelObject = await channel.Receiver.Receive(); + /// var message = (string)channelObject.Data; + /// Console.WriteLine("Received message = " + message); + /// }); + /// + /// + /// + /// 12 + public void Post(Func task) + { + if (task == null) + { + throw new ArgumentNullException(nameof(task)); + } + + int id; + lock (_idLock) + { + if (_id + 1 < 0) _id = 1; + id = _id++; + } + _taskMap[id] = task; + Interop.LibTizenCore.ErrorCode error = Interop.LibTizenCore.TizenCore.AddIdleJob(_handle, NativeTaskCallback, (IntPtr)id, out IntPtr handle); + if (error != Interop.LibTizenCore.ErrorCode.None) + { + _taskMap.TryRemove(id, out var _); + TCoreErrorFactory.CheckAndThrownException(error, "Failed to add idle job"); + } + } + + /// + /// Adds a recurring timer to a main loop of the task. + /// + /// The interval of the timer in milliseconds. + /// The recurring timer callback function which returns whether or not to continue triggering the timer. + /// The registered timer ID to be used with . + /// Thrown when the callback argument is null. + /// Thrown when failed because of the instance is invalid. + /// Thrown when out of memory. + /// + /// The callback function will be called every time the specified interval elapses. It should return true to keep the timer running, otherwise the timer will be stopped. + /// + /// + /// + /// + /// var task = TizenCore.Find("TimerTask") ?? TizenCore.Spawn("TimerTask"); + /// var timerId = task.AddTimer(1000, () => { + /// Console.WriteLine("Timer callback is invoked"); + /// return true; + /// }); + /// + /// + /// + /// 12 + public int AddTimer(uint interval, Func callback) + { + if (callback == null) + { + throw new ArgumentNullException(nameof(callback)); + } + + int id; + lock (_idLock) + { + if (_id + 1 < 0) _id = 1; + id = _id++; + } + var timerSource = new TimerSource(id, IntPtr.Zero, callback); + _timerMap[id] = timerSource; + lock (timerSource) + { + Interop.LibTizenCore.ErrorCode error = Interop.LibTizenCore.TizenCore.AddTimer(_handle, interval, NativeTimerCallback, (IntPtr)id, out IntPtr handle); + if (error != Interop.LibTizenCore.ErrorCode.None) + { + _timerMap.TryRemove(id, out var _); + TCoreErrorFactory.CheckAndThrownException(error, "Failed to add a timer"); + } + + timerSource.Handle = handle; + } + return id; + } + + /// + /// Removes the registered timer from the main loop of the task. + /// If the specified timer was already stopped, no action occurs. + /// + /// The registered timer ID. + /// + /// + /// + /// var task = TizenCore.Find("TimerTask") ?? TizenCore.Spawn("TimerTask"); + /// var timerId = task.AddTimer(1000, () => { + /// Console.WriteLine("Timer handler is invoked"); + /// return true; + /// }); + /// ... + /// task.RemoveTimer(timerId); + /// + /// + /// + /// 12 + public void RemoveTimer(int id) + { + if (_timerMap.TryRemove(id, out var timerSource)) + { + lock (timerSource) + { + if (timerSource.Handle != IntPtr.Zero) + { + Interop.LibTizenCore.TizenCore.RemoveSource(_handle, timerSource.Handle); + timerSource.Handle = IntPtr.Zero; + } + } + } + } + + /// + /// Adds a channel receiver to a main loop of the task. + /// + /// The channel receiver instance. + /// Thrown when the argument is null. + /// Thrown when the argument is invalid. + /// Thrown when out of memory. + /// + /// + /// + /// var channel = new Channel(); + /// var task = TizenCore.Find("ReceivingTask") ?? TizenCore.Spawn("ReceivingTask"); + /// var receiver = channel.Receiver; + /// receiver.Received += (sender, args) => { + /// Console.WriteLine("OnChannelMessageReceived. Message = " + (string)args.Data); + /// }; + /// task.AddChannelReceiver(receiver); + /// + /// + /// + /// 12 + public void AddChannelReceiver(ChannelReceiver receiver) + { + if (receiver == null) { throw new ArgumentNullException(nameof(receiver)); } + + if (receiver.Handle == IntPtr.Zero) + { + throw new ArgumentException("The receiver is already added"); + } + + int id; + lock (_idLock) + { + if (_id + 1 < 0) _id = 1; + id = _id++; + } + receiver.Id = id; + _channelMap[id] = receiver; + lock (receiver) + { + Interop.LibTizenCore.ErrorCode error = Interop.LibTizenCore.TizenCore.AddChannel(_handle, receiver.Handle, NativeChannelReceiveCallback, (IntPtr)id, out IntPtr handle); + if (error != Interop.LibTizenCore.ErrorCode.None) + { + _channelMap.TryRemove(id, out var _); + TCoreErrorFactory.CheckAndThrownException(error, "Failed to add a channel to the task"); + } + + receiver.Source = handle; + receiver.Handle = IntPtr.Zero; + } + } + + /// + /// Removes the registered channel receiver from the main loop of the task. + /// + /// The channel receiver instance. + /// Thrown when the argument is null. + /// Thrown when the argument is invalid. + /// + /// + /// + /// var channel = new Channel(); + /// var task = TizenCore.Find("ReceivingTask") ?? TizenCore.Spawn("ReceivingTask"); + /// var receiver = channel.Receiver; + /// receiver.Received += (sender, args) => { + /// Console.WriteLine("OnChannelMessageReceived. Message = " + (string)args.Data); + /// }; + /// + /// task.AddChannelReceiver(receiver); + /// task.RemoveChannelReceiver(receiver); + /// + /// + /// + /// 12 + public void RemoveChannelReceiver(ChannelReceiver receiver) + { + if (receiver == null) + { + throw new ArgumentNullException(nameof(receiver)); + } + + if (receiver.Id == 0 || receiver.Source == IntPtr.Zero) + { + throw new ArgumentException("Invalid argument"); + } + + if (_channelMap.TryRemove(receiver.Id, out var _)) + { + lock (receiver) + { + if (receiver.Source != IntPtr.Zero) + { + Interop.LibTizenCore.TizenCore.RemoveSource(_handle, receiver.Source); + receiver.Source = IntPtr.Zero; + receiver.Id = 0; + } + } + } + } + + /// + /// Adds an event to a main loop of the task. + /// If the event is successfully added, its unique identifier is assigned to the event. The identifier can then be used later to identify the specific event among others. + /// + /// The event instance. + /// Thrown when the argument is null. + /// Thrown when the argument is invalid. + /// Thrown when out of memory. + /// + /// This method allows you to associate an event with a specific task. By adding an event to a task's main loop, other threads can utilize this event to communicate with the task. + /// However, note that once an event is attached to a task, it cannot be reused or attached to another task. + /// If the argument passed to this method is null, an exception will be thrown. Additionally, if the event has been previously added, an argument exception will be raised. + /// + /// + /// + /// + /// var coreEvent = new Event(); + /// coreEvent.EventReceived += (sender, args) => { + /// Console.WriteLine("OnEventReceived. ID = {}, Message = {}", args.Id, (string)args.Data); + /// }; + /// + /// var task = TizenCore.Find("EventTask") ?? TizenCore.Spawn("EventTask"); + /// task.AddEvent(coreEvent); + /// + /// + /// + /// 12 + public void AddEvent(Event coreEvent) + { + if (coreEvent == null) + { + throw new ArgumentNullException(nameof(coreEvent)); + } + + if (coreEvent.Handle == IntPtr.Zero) + { + throw new ArgumentException("The event is already added"); + } + + int id; + lock (_idLock) + { + if (_id + 1 < 0) + { + _id = 1; + } + id = _id++; + } + coreEvent.Id = id; + _eventMap[id] = coreEvent; + lock (coreEvent) + { + Interop.LibTizenCore.ErrorCode error = Interop.LibTizenCore.TizenCore.AddEvent(_handle, coreEvent.Handle, out IntPtr handle); + if (error != Interop.LibTizenCore.ErrorCode.None) + { + _eventMap.TryRemove(id, out var _); + TCoreErrorFactory.CheckAndThrownException(error, "Failed to add an event to the task"); + } + + coreEvent.Source = handle; + coreEvent.Handle = IntPtr.Zero; + } + } + + /// + /// Removes the registered event from the main loop of the task. + /// + /// The event instance. + /// Thrown when the argument is null. + /// Thrown when the argument is invalid. + /// + /// + /// + /// var coreEvent = new Event(); + /// coreEvent.EventReceived += (sender, args) => { + /// Console.WriteLine("OnEventReceived. ID = {}, Message = {}", args.Id, (string)args.Data); + /// }; + /// + /// var task = TizenCore.Find("EventTask") ?? TizenCore.Spawn("EventTask"); + /// task.AddEvent(coreEvent); + /// task.RemoveEvent(coreEvent); + /// + /// + /// + /// 12 + public void RemoveEvent(Event coreEvent) + { + if (coreEvent == null) + { + throw new ArgumentNullException(nameof(coreEvent)); + } + + if (coreEvent.Id == 0 || coreEvent.Source == IntPtr.Zero) + { + throw new ArgumentException("Invalid argument"); + } + + if (_eventMap.TryRemove(coreEvent.Id, out var _)) + { + lock (coreEvent) + { + if (coreEvent.Source != IntPtr.Zero) + { + Interop.LibTizenCore.TizenCore.RemoveSource(_handle, coreEvent.Source); + coreEvent.Source = IntPtr.Zero; + coreEvent.Id = 0; + } + } + } + } + + /// + /// Emits the event object to all registered event handlers of the task. + /// It's similar to Event.Emit(), but EmitAllEvent() sends the event object to every event handler of the task while Event.Emit() sends the event object only to the target event's event handler. + /// + /// The event object instance. + /// Thrown when the argument is null. + /// Thrown when the argument is invalid. + /// + /// + /// + /// int id = 0; + /// string message = "Test Event"; + /// using (var eventObject = new TCoreEventObject(id++, message)) + /// { + /// var task = TizenCore.Find("EventTask") ?? TizenCore.Spawn("EventTask"); + /// task.EmitEvent(eventObject); + /// } + /// + /// + /// + /// 12 + public void EmitEvent(EventObject eventObject) + { + if (eventObject == null) + { + throw new ArgumentNullException(nameof(eventObject)); + } + + Interop.LibTizenCore.ErrorCode error = Interop.LibTizenCore.TizenCore.EmitEvent(_handle, eventObject.Handle); + TCoreErrorFactory.CheckAndThrownException(error, "Failed to emit event"); + eventObject.Handle = IntPtr.Zero; + } + + private static bool NativeTaskCallback(IntPtr userData) + { + int taskId = (int)userData; + if (_taskMap.TryRemove(taskId, out Func task)) + { + task(); + } + return false; + } + + private static bool NativeActionCallback(IntPtr userData) + { + int actionId = (int)userData; + if (_actionkMap.TryRemove(actionId, out Action action)) + { + action(); + } + return false; + } + + private static bool NativeTimerCallback(IntPtr userData) + { + int timerId = (int)userData; + if (_timerMap.TryGetValue(timerId, out TimerSource timerSource)) + { + bool result = false; + lock (timerSource) + { + if (timerSource.Handle != IntPtr.Zero) + { + result = timerSource.Handler(); + if (!result) + { + _timerMap.TryRemove(timerId, out TimerSource unusedSource); + } + } + } + return result; + } + return false; + } + + private static void NativeChannelReceiveCallback(IntPtr nativeObject, IntPtr userData) + { + int channelId = (int)userData; + if (_channelMap.TryGetValue(channelId, out ChannelReceiver receiver)) + { + lock (receiver) + { + if (receiver.Source != IntPtr.Zero) + { + using (var channelObject = new ChannelObject(nativeObject)) + { + var eventArgs = new ChannelReceivedEventArgs(channelObject); + receiver.InvokeEventHandler(null, eventArgs); + } + } + } + } + } + + internal static Task Find(string id) + { + if (_coreTaskMap.TryGetValue(id, out Task task)) { return task; } + + Interop.LibTizenCore.ErrorCode error = Interop.LibTizenCore.TizenCore.Find(id, out IntPtr handle); + if (error == Interop.LibTizenCore.ErrorCode.None) + { + return new Task(handle); + } + + return null; + } + + internal static Task Spawn(string id) + { + if (id == "main") + { + Log.Error("Invalid argument. id = {}", id); + return null; + } + + var task = new Task(id); + task.Run(); + return task; + } + + /// + /// Checks whether the task is running or not. + /// + /// 12 + public bool Running { + get + { + Interop.LibTizenCore.TizenCore.TaskIsRunning(_handle, out bool running); + return running; + } + } + + /// + /// Runs the main loop of the task. + /// + /// Thrown when the unmanaged handle is invalid. + /// Thrown when failed because of an invalid operation. + /// + /// + /// + /// var coreTask = new TCoreTask("Runner"); + /// coreTask.Run(); + /// + /// + /// + /// 12 + public void Run() + { + Interop.LibTizenCore.ErrorCode error = Interop.LibTizenCore.TizenCore.TaskRun(_handle); + TCoreErrorFactory.CheckAndThrownException(error, "Failed to run task"); + } + + /// + /// Quits the main loop of the task. + /// + /// Thrown when the unmanaged handle is invalid. + /// Thrown when failed because of an invalid operation. + /// + /// This function can be called from any thread. + /// It requests the task to finish the current iteration of its loop and stop running. + /// All pending events in the event queue will be processed before quitting. Once the task quits, it's finished. + /// To start another task, you need to create a new one and call the method on it. + /// + /// + /// + /// + /// var coreTask = new TCoreTask("Runner"); + /// coreTask.Run(); + /// if (coreTask.Running) + /// { + /// coreTask.Quit(); + /// } + /// + /// + /// + /// 12 + public void Quit() + { + Interop.LibTizenCore.ErrorCode error = Interop.LibTizenCore.TizenCore.TaskQuit(_handle); + TCoreErrorFactory.CheckAndThrownException(error, "Failed to quit task"); + } + + /// + /// Release any unmanaged resources used by this object. + /// + /// If true, disposes any disposable objects. If false, does not dispose disposable objects. + /// 12 + protected virtual void Dispose(bool disposing) + { + if (!_disposed) + { + if (disposing) + { + if (_handle != IntPtr.Zero) + { + if (Running) + { + Quit(); + } + + Interop.LibTizenCore.TizenCore.TaskDestroy(_handle); + _handle = IntPtr.Zero; + } + } + + _disposed = true; + } + } + + /// + /// Release any unmanaged resources used by this object. + /// + /// 12 + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + internal class TimerSource + { + public TimerSource(int id, IntPtr handle, Func handler) + { + Id = id; + Handle = handle; + Handler = handler; + } + + public int Id { get; set; } + + public IntPtr Handle { get; set; } + + public Func Handler { get; set; } + } + } +} diff --git a/src/Tizen.Core/Tizen.Core/TizenCore.cs b/src/Tizen.Core/Tizen.Core/TizenCore.cs new file mode 100644 index 00000000000..62057768979 --- /dev/null +++ b/src/Tizen.Core/Tizen.Core/TizenCore.cs @@ -0,0 +1,168 @@ +/* + * Copyright (c) 2024 Samsung Electronics Co., Ltd All Rights Reserved + * + * 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. + */ + +using System; + +namespace Tizen.Core +{ + /// + /// The class which provides functions related to the Tizen Core. + /// + public static class TizenCore + { + /// + /// Initializes Tizen Core. + /// This method should be called once per application before creating any Tasks. + /// Calling this method more than one time will increase internal reference counts which need to be matched by calling Shutdown(). + /// Failing to call Shutdown() in corresponding number of calls may cause resource leakages. + /// + /// + /// + /// + /// TizenCore.Initialize(); + /// var task = TizenCore.Spawn("Worker"); + /// + /// + /// + /// 12 + static public void Initialize() + { + Interop.LibTizenCore.TizenCore.Init(); + } + + /// + /// Shuts down Tizen Core. + /// + /// + /// + /// + /// TizenCore.Shutdown(); + /// + /// + /// + /// 12 + static public void Shutdown() + { + Interop.LibTizenCore.TizenCore.Shutdown(); + } + + /// + /// Finds the task instance. + /// + /// The ID of the task. + /// + /// + /// + /// TizenCore.Initialize(); + /// var task = TizenCore.Find("Test") ?? TizenCore.Spawn("Test"); + /// + /// + /// + /// On success the task instance, othwerwise null. + public static Task Find(string id) + { + return Task.Find(id); + } + + /// + /// Finds the task instance running in the thread of the caller or the "main" task. + /// + /// On success the task instance, othwerwise null. + /// + /// + /// + /// TizenCore.Initialize(); + /// var coreTask = TizenCore.FindFromThisThread(); + /// if (coreTask != null) + /// { + /// coreTask.Post(() => { + /// Console.WriteLine("Idler invoked"); + /// }); + /// } + /// + /// + /// + /// 12 + public static Task FindFromCurrentThread() + { + Interop.LibTizenCore.ErrorCode error = Interop.LibTizenCore.TizenCore.FindFromThisThread(out IntPtr handle); + if (error == Interop.LibTizenCore.ErrorCode.None) + { + return new Task(handle); + } + + return null; + } + + /// + /// Creates and runs the task. + /// + /// The ID of the task. + /// On succes the created task instance, othwerwise null. + /// + /// + /// + /// TizenCore.Initialize(); + /// var task = TizenCore.Spawn("Worker"); + /// if (task != null) + /// { + /// task.AddTimer(5000, () => { + /// Console.WriteLine("Timer expired"); + /// return true; + /// }); + /// } + /// + /// + /// + /// 12 + public static Task Spawn(string id) + { + return Task.Spawn(id); + } + } + + internal static class TCoreErrorFactory + { + internal enum TCoreError + { + None = Interop.LibTizenCore.ErrorCode.None, + InvalidParameter = Interop.LibTizenCore.ErrorCode.InvalidParameter, + OutOfMemory = Interop.LibTizenCore.ErrorCode.OutOfMemory, + InvalidContext = Interop.LibTizenCore.ErrorCode.InvalidContext, + } + + static internal void CheckAndThrownException(Interop.LibTizenCore.ErrorCode error, string message) + { + if ((TCoreError)error == TCoreError.None) + { + return; + } + + if ((TCoreError)error == TCoreError.InvalidParameter) + { + throw new ArgumentException(message); + } + else if ((TCoreError)error == TCoreError.OutOfMemory) + { + throw new OutOfMemoryException(message); + } + else if ((TCoreError)error == TCoreError.InvalidContext) + { + throw new InvalidOperationException(message); + } + } + } +} diff --git a/src/Tizen.Core/doc/api/Tizen.Core.md b/src/Tizen.Core/doc/api/Tizen.Core.md new file mode 100644 index 00000000000..2ec04f67c0a --- /dev/null +++ b/src/Tizen.Core/doc/api/Tizen.Core.md @@ -0,0 +1,177 @@ +--- +# Copyright (c) 2024 Samsung Electronics Co., Ltd All Rights Reserved +# +# 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. + +uid: Tizen.Core +summary: Tizen Core (TCore) is a new main loop model that provides per thread loops, message and event transmission, uniquely named threads. +remarks: *content +--- +## Overview +Tizen Core (TCore) is a new main loop that improves the existing main loop model. It supports creating and running the main loop in multiple threads. Tizen Core provides an API that supports secure communication between threads. + +## Preparation +To use the Tizen Core API, you must define `using Tizen.Core`, as shown below: +```cs +using Tizen.Core; +``` + +## Initializing Tizen Core +Before using Tizen Core, Calls TizenCore.Initialize() as shown below: +```cs +TizenCore.Initialize(); +``` + +## Shutting down Tizen Core +When Tizen Core is no longer needed, shut down Tizen Core with the code below: +```cs +TizenCore.Shutdown(); +``` + +## Managing Tizen Core tasks +This section will cover creating, executing, and terminating the CoreTask objects, It will also cover adding idle jobs and timers to the main loop. + +### Creating a task +Here` an example on how to create a Task object: +```cs +{ + TizenCore.Initialize(); + var task = new Task("task1"); +} +``` +`task` was created with the name "task1" and configured to use its own thread. The created `task` instance should be removed using `Dispose()` method when it is no longer needed. + +### Running a task +In this example, we'll cover the code to execute a previously created task: +```cs +{ + task.Run(); +} +``` +`task` creates and runs a thread named "task1". After calling `Run()` method, the thread is created and the loop starts running. + +### Checking if a task is running +An example of checking if a task is running using `Running` property: +```cs +{ + if (task.Running) + { + Log.Debug(LogTag, "task1 is running"); + } + else + { + Log.Debug(LogTag, "task1 is not running"); + } +} +``` + +### Adding an timer job to Tizen Core +Here's an example of registering a timer that calls the handler every 100 ms. +```cs +{ + var timerId = task.AddTimer(100, () => { + Log.Debug(LogTag, "timer handler is invoked"); + return true; + }); +} +``` + +### Adding an action to Tizen Core +Let'w write an example that adds an action to `Task`. +```cs +{ + var task = TizenCore.Find("Test") ?? TizenCore.Spawn("Test"); + task.Post(() => { + Log.Debug(LogTag, "Action is invoked"); + }); +} +``` + +## Managing Tizen Core channels +Tizen Core channel Provides a communication channel that allows safe sending and receiving of data between threads. This channel can be used to exchange information in a synchronized state without data conflict. This section describes how to create a channel sender and receiver pair, send and receive data, and destroy the channel sender and receiver pair. + +### Creating a channel +Here'a an example on how to create a Channel object: +```cs +{ + try { + var channel = new Channel(); + } + catch (OutOfMemoryException) + { + Log.Error(LogTag, "Exception occurs"); + } +} +``` + +### Creating and transmitting a channel object +This example show how to create and transmit a channel object: +```cs +{ + TizenCore.Initialize(); + var channel = new Channel(); + var receiver = channel.Receiver; + receiver.Received += (s, e) => { + Log.Debug(LogTag, "OnChannelObjectReceived. Message = {}", (string)e.Data); + }; + + var task = TizenCore.Find("ReceivingTask") ?? TizenCore.Spawn("ReceivingTask"); + task.AddChannelReceiver(receiver); + + var sender = channel.Sender; + string message = "Test message"; + using (var channelObject = new ChannelObject(1, message)) + { + sender.Send(channelObject); + } +} +``` +The example shows adding a receiver to a ReceivingTask and delivering a message using a ChannelSender. +The channel event is passed to the main loop of the ReceivingTask, causing the event handler to be called. + +## Managing Tizen Core events +A feature to deliver events to specific tasks, which can be used to wait for completion of tasks or send notifications to other threads. This section covers creating events, registering event handlers with them, attaching them to the main loop, and receiving events. + +### Creating an event and registering an event handler +Here's an example of creating an event and registering an event handler: +```cs +{ + var coreEvent = new Event(); + coreEvent.EventReceived += (s, e) => { + Log.Debug(LogTag, "OnEventReceived. Message = {}", (string)e.Data); + } +} +``` +The example shows creating an event and registering an event handler for it. The created event is added to the EventTask. + +### Creating an event object and delivering it to the task. +```cs +{ + TizenCore.Initialize(); + var coreEvent = new Event(); + coreEvent.EventReceived += (s, e) => { + Log.Debug(LogTag, "OnEventReceived. Message = {}", (string)e.Data); + } + + var task = TizenCore.Find("EventTask") ?? TizenCore.Spawn("EventTask"); + task.AddEvent(coreEvent); + + string message = "Event message"; + using (var eventObject = new EventObject(1, message)) + { + task.EmitEvent(eventObject); + } +} +``` +The generated event is added to an EventTask, and a corresponding EventObject is passed to it. +The event is then delivered to the main loop of the EventTask where the EventHandler is called.