Run a thread continuously without blocking main thread in swift - swift

I wrote a code and I need to run it continuously. Initially I used RunLoop.current.run(). It works fine. The problem is it blocks the main thread. How can I run it in background continuously without blocking.
Basic class structure:
class Keylogger
{
func start()
{
let observer = UnsafeMutableRawPointer(Unmanaged.passUnretained(self).toOpaque())
/* Connected and Disconnected Call Backs */
IOHIDManagerRegisterDeviceMatchingCallback(manager, Handle_DeviceMatchingCallback, observer)
IOHIDManagerRegisterDeviceRemovalCallback(manager, Handle_DeviceRemovalCallback, observer)
/* Input value Call Backs */
IOHIDManagerRegisterInputValueCallback(manager, Handle_IOHIDInputValueCallback, observer);
/* schedule */
IOHIDManagerScheduleWithRunLoop(manager, CFRunLoopGetMain(), CFRunLoopMode.defaultMode.rawValue)
print("Started")
}
}
And in main.swift
var logger = Keylogger()
logger.start()
RunLoop.current.run()
// Whatever written below this will not be executed obviously
I used DispatchQueue before for background tasks( which is just a piece of code) but how to execute it continuously?
I tried this:
var d = Keylogger()
var ff = {
d.start()
}
var f = DispatchQueue(label: "Keylogger", qos: .userInteractive, attributes: .concurrent)
f.async(execute: ff)
while true
{}
But the start() of Keylogger is never executed.
I thought of creating executable and running the executable through NSTask. Other than this is there any way to do it?

I think you are not understanding the purpose of RunLoop.current.run().
Your code works only when your program is running. Constantly.
Your keylogger code is ran on an another thread. So, to keep that thread alive, the main thread must be active. That is the reason for RunLoop.current.run().
So, try to use callbacks(like keylogger is using) and schedule it on another thread. Or, do everything you want and place RunLoop.current.run() at the very end of your code.

Related

FreeRTOS ignores osDelay [STM32]

I am new here, but have often benefited from questions and their results.
Now I have a problem that I can not solve for days. It is about a STM32L431RCT6 with FreeRTOS. There are 3 tasks running on it. Two of them are dedicated to processing CanOpenNode (1 to send data, 1 to receive). One is a custom controller. The code works as it is, but when I enable the CRC unit (MX_CRC_Init()) the problem appears. With the CRC unit enabled, only the task to receive the data from Canopen is executed. The other tasks are set to "Ready". What I notice is that the osDelay() used in the receive task seems to be ignored. It doesn't seem to matter if I use osDelay(1) or osDelay(10000).
void start_CO_rec_Thread(void *argument)
{
/* USER CODE BEGIN start_CO_TI_Thread */
/* Infinite loop */
for(;;)
{
canopen_app_interrupt();
osDelay(1);
}
osThreadTerminate(NULL);
/* USER CODE END start_CO_TI_Thread */
}
Something else is added. If I remove functions and variables in the task by starting an own controller, the processing of the tasks works again. Now I have concluded that the tasks need more stack memory. But this is also not the solution of the puzzle...
Working Code:
void Start_Controller(void *argument)
{
Sensor = new DS18B20(htim6);
Regler = new Smithpredictor(Sensor);
// osTimerStart(LifetimerHandle, 1000);
for(;;)
{
if (global_state==4)
actual_Temperatur = Regler->run(target_Temperature);
osDelay(MBC_intervall_s*1000);
}
osThreadTerminate(NULL);
}
Not Working Code:
void Start_Controller(void *argument)
{
Sensor = new DS18B20(htim6);
Regler = new Smithpredictor(Sensor);
osTimerStart(LifetimerHandle, 1000);
for(;;)
{
if (global_state==4)
actual_Temperatur = Regler->run(target_Temperature);
osDelay(MBC_intervall_s*1000);
}
osThreadTerminate(NULL);
}
I hope someone has an idea how to proceed or can help me. Even if it is just another way to further identify the problem. Maybe I have also committed some stupidity, I am unfortunately not a computer scientist.

No events received when using DispatchSource.makeFileSystemObjectSource() to monitor changes to file

I found this article about watching for changes and I've tried to follow along properly. My dispatch source gets created, but I never receive any events.
To make sure I was getting anything and everything, I made sure to set the eventMask = .all.
override func viewDidAppear() {
super.viewDidAppear()
Task {
self.configurl = await self.openfile(forkey: self.keybookmarkconfig)
if let url = self.configurl {
print("creating filehandle for \(url.absoluteString)")
self.configfilehandle = try FileHandle(forReadingFrom: url)
print("creating dispatch source to watch \(url.absoluteString)")
self.source = DispatchSource.makeFileSystemObjectSource(
fileDescriptor: self.configfilehandle.fileDescriptor,
eventMask: .all,
queue: DispatchQueue.main
)
print("setting event handler for dispatch source")
self.source.setEventHandler {
print("config file changed")
}
print("done with watcher setup")
}
}
}
I tried updating the file in numerous ways. I edited/saved it in BBEdit and TextEdit, but because of the warning about how those types of editors might delete/recreate the file, also I tried editing it from the command line with vim. I even did echo "test" >> myfile.txt. But I never received any events in my event handler. I restarted my app in between each of these tests, so I had a fresh file handle.
Any idea why I'm not receiving any event callbacks?
After the dispatch source has been created, you have to call self.source.activate() so that the source gets scheduled and started. Otherwise it's just sitting there.
From the documentation:
After creating the dispatch source, use the methods of the DispatchSourceProtocol protocol to install the event handlers you need. The returned dispatch source is in the inactive state initially. When you are ready to begin processing events, call its activate() method.

Will an item submitted to the main `DispatchQueue` ever interrupt currently executing code on the main thread?

The below code is used to execute a long running calculation on a background thread:
enum CalculationInterface {
private static var latestKey: AnyObject? // Used to cancel previous calculations when a new one is initiated.
static func output(from input: Input, return: #escaping (Output?) -> ()) {
self.latestKey = EmptyObject()
let key = self.latestKey! // Made to enable capturing `self.latestKey's` value.
DispatchQueue.global().async {
do {
let output = try calculateOutput(from: input, shouldContinue: { key === self.latestKey }) // Function cancels by throwing an error.
DispatchQueue.main.async { if (key === self.latestKey) { `return`(output) } }
} catch {}
}
}
}
This function is called from the main thread like so:
/// Initiates calculation of the output and sets it to the result when finished.
private func recalculateOutput() {
self.output = .calculating // Triggers calculation in-progress animation for user.
CalculationInterface.output(from: input) { self.output = $0 } // Ends animation once set and displays calculated output to user.
}
I'm wondering if it's possible for the closure that's pushed to DispatchQueue.main to execute while the main thread is running my code. Or in other words execute after self.output = .calculating but before self.latestKey is re-set to the new object. If it could, then the stale calculation output could be displayed to the user.
I'm wondering if it's possible for the closure that's pushed to DispatchQueue.main to execute while the main thread is running my code
No, it isn't possible. The main queue is a serial queue. If code is running on the main queue, no "other" main queue code can run. Your DispatchQueue.main.async effectively means: "Wait until all code running on the main queue comes naturally to an end, and then run this on the main queue."
On the other hand, DispatchQueue.global() is not a serial queue. Thus it is theoretically possible for two calls to calculateOutput to overlap. That isn't something you want to have happen; you want to be sure that any executing instance of calculateOutput finishes (and we proceed to grapple with the latestKey) before another one can start. In other words, you want to ensure that the sequence
set latestKey on the main thread
perform calculateOutput in the background
look at latestKey on the main thread
happens coherently. The way to ensure that is to set aside a DispatchQueue that you create with DispatchQueue(label:), that you will always use for running calculateOutput. That queue will be a serial queue by default.

Why event flag related functions does not work correctly outside of tasks in keil rtx?

As you know event flags are very useful (e.g. let task running),but unfortunately their control functions (os_evt_clr/set/wait) does not work outside of tasks bodies correctly(e.g. in interrupt handling functions). For alternative i used a variable ,I initialized it in Interrupt handler when needed ,then used it on another task to running a os_evt_set() function for let MCU entering a task.
bool Instance_Variable;
Interrupt_Handler()
{
if(xxxx)
Instance_Variable=1
}
//--------------------------
Secondary_Task()
{
//This is frequently run task
if(Instance_Variable==1)
{
os_evt_set (0x0001, Primary_Task_ID);
Instance_Variable=0;
}
}
//--------------------------
Primary_Task()
{
Result = os_evt_wait_or (0x0001, 0xFFFF);
//Task's body
os_evt_clr (0x0001, Primary_Task_ID);
}
Any better approach?WBR.
You can't use function prefixed with os_ inside ISR. Usage hints from RTX documentation:
Functions that begin with os_ can be called from a task, but not from an interrupt service routine.
Functions that begin with isr_ can be called from an IRQ interrupt service routine but not from a task.
This code will work:
Interrupt_Handler() {
if(xxxx) {
isr_evt_set (0x0001, Primary_Task_ID);
}
}
//--------------------------
Primary_Task() {
Result = os_evt_wait_or (0x0001, 0xFFFF);
//Task's body
os_evt_clr (0x0001, Primary_Task_ID);
}

running main thread frm another thread

I have run a secondary thread which some operations are carried on. Then while executing in secondary thread i want to call some operations on main thread. Can any one have sample code for it. I could not find it from google.
Here is my sample call:
Glib::thread_init();
Glib::Thread *const myThread = Glib::Thread::create(sigc::mem_fun(*this, &MyClass::MyFunction), true);
myThread->join();
MyClass::MyFunction()
{
//here i want to call the function from main thread
AnotherFunction();
}
MyClass::AnotherFunction()
{
}