Difference between GetWorkLoop()->runAction and GetCommandGate()->runAction? - macos

This has been confusing me for a long time.
In my IOkit driver,I registered interrupt event source, timer event source to workloop. and I use GetWorkLoop()->runAction(pAction) for hardware access.
so, all hardware access from interrupt handler and timer handler and my pAction are serialized.
But, I found another runAction from IOCommandGate. I wonder the difference between the two runAction.
I looked into some iokit kernel docs.didn't get a clear answer.
In xnu source:
IOReturn IOWorkLoop::runAction(Action inAction, OSObject *target,
void *arg0, void *arg1,
void *arg2, void *arg3)
{
IOReturn res;
// closeGate is recursive so don't worry if we already hold the lock.
closeGate();
res = (*inAction)(target, arg0, arg1, arg2, arg3);
openGate();
return res;
}
I means when I call GetWorkLoop()->runAction(inAction). inAction is run in my thread context, not in workloop thread context. is this correct?
IOReturn IOCommandGate::runAction(Action inAction,
void *arg0, void *arg1,
void *arg2, void *arg3)
{
if (!inAction)
return kIOReturnBadArgument;
// closeGate is recursive needn't worry if we already hold the lock.
closeGate();
// If the command gate is disabled and we aren't on the workloop thread
// itself then sleep until we get enabled.
IOReturn res;
if (!workLoop->onThread()) {
while (!enabled) {
uintptr_t *sleepersP = (uintptr_t *) &reserved;
*sleepersP += 2;
IOReturn res = sleepGate(&enabled, THREAD_ABORTSAFE);
*sleepersP -= 2;
bool wakeupTearDown = (*sleepersP & 1);
if (res || wakeupTearDown) {
openGate();
if (wakeupTearDown)
commandWakeup(sleepersP); // No further resources used
return kIOReturnAborted;
}
}
}
bool trace = ( gIOKitTrace & kIOTraceCommandGates ) ? true : false;
if (trace)
IOTimeStampStartConstant(IODBG_CMDQ(IOCMDQ_ACTION),
VM_KERNEL_UNSLIDE(inAction), (uintptr_t) owner);
IOStatisticsActionCall();
// Must be gated and on the work loop or enabled
res = (*inAction)(owner, arg0, arg1, arg2, arg3);
if (trace)
IOTimeStampEndConstant(IODBG_CMDQ(IOCMDQ_ACTION),
VM_KERNEL_UNSLIDE(inAction), (uintptr_t) owner);
openGate();
return res;
}
the code seems GetCommandGate()->runAction also run in my thread context. not workloop thread?

You are correct, in both cases your action will be run in the context of the current thread, not the IOWorkLoop thread. It is guaranteed that the IOWorkLoop will not be running any actions (secondary interrupt handlers, etc.) on its thread while your action is running however.
The difference between the two, as you can see, is that the IOCommandGate can be disabled and re-enabled to pause running of actions. I have not needed this in practice, but maybe it comes in useful sometimes.
To run actions on the IOWorkLoop thread itself, an IOEventSource subclass must override the checkForWork() virtual method, and notify the IOWorkLoop of new work via the IOEventSource's signalWorkAvailable() method.
I'm not aware of a general-purpose event source you can use which allows you to queue arbitrary jobs to run on the IOWorkLoop thread, other than IOCommandQueue which has been deprecated for many years. (so you should not use that)

Related

Suspending(), Resuming(), Closed() and Uninitialize() are not being called in IFrameworkView

I've written a simple DirectX11.2 app, which works. I wanted to add some cleanup code for when the app exits, however I noticed that my window does not actually handle closing, suspending, resuming or uninitializing properly.
According to the IFrameworkView documentation, Uninitialize() should get called before the application exits, but it never gets called (https://learn.microsoft.com/en-us/uwp/api/windows.applicationmodel.core.iframeworkview?view=winrt-19041)
I subscribe to the events that are supposed to fire when a window suspends, resumes, or closes, however it seems like none of those events ever actually fire.
I am under the impression that minimizing the window should suspend the application, clicking on the window from the task bar after it has been minimized should resume the application, and pressing the red X button in the top right corner of the window should close the application, am I wrong?
Here is the relevant code:
// the class definition for the core "framework" of our app
ref class App sealed: public IFrameworkView
{
bool m_windowClosed;
CGame m_game;
public:
// this function subscribes to suspend and resume events, and gets called properly
virtual void Initialize(CoreApplicationView^ appView) {
// set the OnActivated function to handle to Acivated "event"
appView->Activated += ref new TypedEventHandler<CoreApplicationView^, IActivatedEventArgs^>(this, &App::OnActivated);
CoreApplication::Suspending += ref new EventHandler<SuspendingEventArgs^>(this, &App::Suspending);
CoreApplication::Resuming += ref new EventHandler<Object^>(this, &App::Resuming);
m_windowClosed = false;
}
// this function subscribes to the close() event. This function is called properly, but the Closed event never fires
virtual void SetWindow(CoreWindow^ window){
window->Closed += ref new TypedEventHandler<CoreWindow^, CoreWindowEventArgs^>(this, &App::Closed);
}
virtual void Load(String^ entryPoint) {}
virtual void Run() {
m_game.Initialize();
CoreWindow^ Window = CoreWindow::GetForCurrentThread();
// repeat until window closes
while (!m_windowClosed) {
// run processEvents() to dispatch events
// ProcessAllIfPresent makes ProcessEvents return once all events have been processed
Window->Dispatcher->ProcessEvents(CoreProcessEventsOption::ProcessAllIfPresent);
// run the rest of the game code here
m_game.Update();
m_game.Render();
}
// we never get here!
m_game.Finalize();
}
// never called, even though it should ALWAYS be called when the application exits?
virtual void Uninitialize() {
Log("Uninitialize()");
}
void OnActivated(CoreApplicationView^ coreAppView, IActivatedEventArgs^ args) {
CoreWindow^ window = CoreWindow::GetForCurrentThread();
window->Activate();
}
// never called
void Suspending(Object^ sender, SuspendingEventArgs^ args) {
Log("Suspending()");
}
// never called
void Resuming(Object^ sender, Object^ args) {
Log("Resuming()");
}
// never called
void Closed(CoreWindow^ sender, CoreWindowEventArgs^ args) {
m_windowClosed = true;
Log("Close()");
}
};
// the class definition that creates an instance of our core framework class
ref class AppSource sealed : IFrameworkViewSource {
public:
virtual IFrameworkView^ CreateView() {
// create an App class and return it
return ref new App();
}
};
[MTAThread] // define main() as a multi-threaded-apartment function
// the starting point of all programs
int main(Array<String^>^ args) {
// create and run a new AppSource class
CoreApplication::Run(ref new AppSource());
return 0;
}
Upon further research, I notice that Suspend and Resume are generally called when Windows itself suspends (sleep, hibernate) and resumes ("wakes up" from sleep or hibernate).
I have now found that the only event that's called before my app terminates is the CoreWindow::VisibilityChanged event.

Why does only some of my objects get created using std::async

I have a loop that pushes back calls of std::async that are used to create objects in the pointed function and emplace them back to another vector. All the calls are pushed to the futures function and the results are ready when i used the VS debugger. However of the 507 calls, only 30 objects are actually created and i cant seem to pin point why.I have tried setting the launch policy to both async and defered but get the same result.
void load_sec_p(vector<Security>* secs, map<string, map<string, vector<daySec>>> *psa_timeline,security sec) {
Security tmp = Security(psa_timeline, &sec.tsymb, &sec.gicsInd);
std::lock_guard<std::mutex> lock(s_SecsMutex);
secs->emplace_back(tmp);
}
Above is the function being executed in the async call
below is the loop that pushes back the futures
for (auto& sec : security_list) {
m_SecFutures.emplace_back(std::async(load_sec_p,&async_secs, &psa_timeline, sec));
}
The following pictures show the watch of both variables after the above loop is completed and the entire future vectors is checked for completion.
I have tried creating the objects by just using a regular for loop and appending them synchronously but it simply just takes too long(2 hours and 11 minutes long). If anyone has any advice on alternatives or how to fix my vector problem it would be greatly appreciated.
The code that checks if all the futures is shown below:
bool done = false;
cout << "Waiting...";
do {
done = futures_ready(m_SecFutures);
} while (!done);
The function is
template<class T>
bool futures_ready(std::vector<std::future<T>>& futures) {
std::chrono::milliseconds span(5);
bool finished = false;
int pends = 0;
while (!finished) {
//allowing thread to sleep so futures can process a bit more and also
//so thread doesnt reach max cpu usage
std::this_thread::sleep_for(std::chrono::milliseconds(100));
for (auto& x : futures) {
if (x.wait_for(span) == std::future_status::timeout) {
++pends;
}
}
if (pends == 0) {
finished = true;
}
else {
pends = 0;
}
}
return finished;
}

app_message_outbox_send is not in app space

I am working on a Pebble watch face and I ran into a problem, the function app_message_outbox_send seems to throw an error (which then crashes my app). The error is "[INFO ] E call_internal.c:36 syscall failure! 0..0x8 is not in app space."
The relevant code:
static void askPhoneForCharge(){
if(bluetooth_connection_service_peek()){
DictionaryIterator *iter;
app_message_outbox_begin(&iter);
dict_write_uint8(iter, KEY_PHONE_ASK, 0);
app_message_outbox_send();
}else{
phoneCharging = 0;
phoneCharge = 0;
updatePhoneBattery();
}
}
Here is how I set up the handlers and open the channel:
app_message_register_inbox_received(inboxReceivedCallback);
app_message_register_inbox_dropped(inboxDroppedCallback);
app_message_register_outbox_failed(outboxFailedCallback);
app_message_register_outbox_sent(outboxSentCallback);
app_message_open(app_message_inbox_size_maximum(), app_message_outbox_size_maximum());
As it turns out, you can not use the message functions while in the initialization phase, so I started a timer that only executes once to take care of the initial messaging.
I was having the same problem while sending the app_message_outbox_send() command which was getting called by to the Up_button_click handler.
The following initialization code in the Init() method fixed it for me.
Look at the "Register message handlers" & "Init buffers"
void out_sent_handler(DictionaryIterator *sent, void *context){}
static void out_fail_handler(DictionaryIterator *failed, AppMessageResult reason, void* context){}
static void in_received_handler(DictionaryIterator *iter, void* context){}
void in_drop_handler(AppMessageResult reason, void *context){}
static void init() {
// Register message handlers
app_message_register_outbox_sent(out_sent_handler);
app_message_register_inbox_received(in_received_handler);
app_message_register_inbox_dropped(in_drop_handler);
app_message_register_outbox_failed(out_fail_handler);
// Init buffers
app_message_open(64, 64);
// Create main Window element and assign to pointer
s_main_window = window_create();
// Set handlers to manage the elements inside the Window
window_set_window_handlers(s_main_window, (WindowHandlers) {
.load = main_window_load,
.unload = main_window_unload
});
// Show the Window on the watch, with animated=true
window_stack_push(s_main_window, true);
}

Real time java - async event handler fails to fire

The following code is adapted from an example in Real-Time Java Platform Programming by Peter C. Dibble:
import javax.realtime.*;
public class OSTimer {
static volatile boolean cont = true;
public static void main(String[] args) {
AsyncEventHandler handler = new AsyncEventHandler(){
public void handleAsyncEvent() {
System.out.println("Stopping...");
cont = false;
}
}
};
OneShotTimer timer = new OneShotTimer(new RelativeTime(3000, 0), handler);
timer.start();
while(cont){
System.out.println("Running");
if (timer.isRunning()) System.out.println("Timer is running");
try {
Thread.sleep(1000);
} catch(Exception e) { }
}
System.exit(0);
}
The the program is supposed to run for 3 seconds and then exit. However, the output shows that while the timer did indeed stop after 3 seconds, the program continues as usual, i.e. output is:
Running
Timer is running
Running
Timer is running
Running
Timer is running
Running
Running
Running......
Clearly the handler did not fire, and I've no idea why. Another example program involving a periodic timer triggering the handler does work as expected. The program structure is almost the same as the one here.
A few things to try:
Call fire() explicitly on the timer instance to see if you can force things
Try creating your handler by passing in the logic as a Runnable object to the handler. The API is a little unclear on this, but this is how I have specified handlers in the past.
Example:
AsyncEventHandler handler = new AsyncEventHandler(new Runnable() {
public void run() {
System.out.println("Stopping...");
cont = false;
}
});

call async_resolve.cancel(),but the callback handler of async_resolve doesn't return boost::asio::error::operation_aborted

i used boost asio to process http request and answer,to avoid async_resolve doesn't invoke its callback handler,i set a timeout,just like this:
void resolve()
{
resolver_.async_resolve(query,strand_.wrap(boost::bind(&connection::handle_resolve,
shared_from_this(),
boost::asio::placeholders::error,
boost::asio::placeholders::iterator)));
int cancel_num = timer_.expires_from_now(boost::posix_time::seconds(resolve_timeout_));
timer_.async_wait(strand_.wrap(boost::bind(&connection::handle_resolve_timeout,
shared_from_this(),
boost::asio::placeholders::error)));
}
void connection::handle_resolve_timeout(const boost::system::error_code& err)
{
if (err != boost::asio::error::operation_aborted)
{
resolver_.cancel();
}
}
void connection::handle_resolve(const boost::system::error_code& err,
boost::asio::ip::tcp::resolver::iterator endpoint_iterator)
{
timer_.cancel();
if(!err)
{
boost::asio::ip::tcp::endpoint endpoint = *endpoint_iterator;
socket_.async_connect(endpoint,strand_.wrap(boost::bind(&connection::handle_connect,
shared_from_this(),
boost::asio::placeholders::error,
++endpoint_iterator)));
//to distinct the type of timeout ,0:connect timeout,1:read timeout
int flag = 0;
int cancel_num = timer_.expires_from_now(boost::posix_time::seconds(connect_timeout_));
timer_.async_wait(strand_.wrap(boost::bind(&connection::handle_timeout,
shared_from_this(),
boost::asio::placeholders::error,
flag)));
}
else if(err != boost::asio::error::operation_aborted)
{
status_ = resolve_error;
check_.do_finish(shared_from_this());
}
else
{
FASTCHECK_INFO("resolve is canceled\n");
}
}
when resolve timeout ,i found the handle_resolve_timeout is invoked,but the handle_resolve doesn't return boost::asio::error::operation_aborted,why,i am puzzled,can someone can explain it for me?
According to the discussion on boost-users mailing list, resolver::cancel() is only able to cancel pending, queued resolve requests, not the one that's currently executing.
As a delayed follow up to #Cubbi's answer, this bug was also raised on the Boost issue tracker a few months after this question's thread. The Asio resolver API is slightly confusing because it suggests that any async_resolve() operation can be cancelled on demand. I had the same problem myself. It also turns out that in the Asio implementation, calls to async_resolve() makes a synchronous system call to getaddrinfo() behind the scenes. I discuss this interesting behavior in a recent codecast.

Resources