What happens when kernel delayed_work is rescheduled - linux-kernel

I am using the kernel shared workqueue, and I have a delayed_work struct that I want to reschedule to run immediately.
Will the following code guarantee that the delayed_work will run as soon as possible?
cancel_delayed_work(work);
schedule_delayed_work(work, 0);
What happens in a situation where the work is already running? cancel_delayed_work will return 0, but I'm not sure what schedule_delayed_work will do if the work is currently running or is unscheduled.

Well, you know what they say about necessity being the mother of all invention (or research in this case). I really needed this answer and got it by digging through kernel/workqueue.c. Although the answer is mostly contained in the doc comments combined with Documentation/workqueue.txt, it isn't clearly spelled out without reading the whole spec on the Concurrency Managed Workqueue (cmwq) subsystem and even then, some of the information is out of date!
Short Answer
Will [your code] guarantee that the delayed_work will run as soon as possible?
Yes (with the below caveat)
What happens in a situation where the work is already running?
It will run at some point after the currently running delayed_work function exits and on the same CPU as the last one, although any other work already queued on that workqueue (or delayed work that is due) will be run first. This is presuming that you have not re-initialized your delayed_work or work_struct object and that you have not changed the work->function pointer.
Long Answer
So first off, struct delayed_work uses pseudo-inheritance to derive from struct work_struct by embedding a struct work_struct as its first member. This subsystem uses some amazing atomic bit-frigging to have some serious concurrency. A work_struct is "owned" when it's data field has the WORK_STRUCT_PENDING bit set. When a worker executes your work, it releases ownership and records the last work pool via the private set_work_pool_and_clear_pending() function -- this is the last time the API modifies the work_struct object (until you re-schedule it, of course). Calling cancel_delayed_work() does the exact same thing.
So if you call cancel_delayed_work() when your work function has already begun executing, it returns false (as advertised) since it is no longer owned by anybody, even though it may still be running. However, when you try to re-add it with schedule_delayed_work(), it will examine the work to discover the last pool_workqueue and then find out if any of that pool_workqueue's workers are currently running your work. If they are (and you haven't changed the work->func pointer), it simply appends the work to the queue of that pool_workqueue and that's how it avoids re-entrancy! Otherwise, it will queue it on the pool for the current CPU. (The reason for the work->func pointer check is to allow for reuse of the work_struct object.)
Note however that simply calling schedule_delayed_work() without cancelling it first will result in no change if the work is still queued, so you definitely must cancel it first.
EDIT: Oh yeah, if you are confused by the discussion in Documentation/workqueue.txt about WQ_NON_REENTRANT, ignore it. This flag is deprecated and ignored and all workqueues are now non-reetrant.

Related

What is the use-case for TryEnterCriticalSection?

I've been using Windows CRITICAL_SECTION since the 1990s and I've been aware of the TryEnterCriticalSection function since it first appeared. I understand that it's supposed to help me avoid a context switch and all that.
But it just occurred to me that I have never used it. Not once.
Nor have I ever felt I needed to use it. In fact, I can't think of a situation in which I would.
Generally when I need to get an exclusive lock on something, I need that lock and I need it now. I can't put it off until later. I certainly can't just say, "oh well, I won't update that data after all". So I need EnterCriticalSection, not TryEnterCriticalSection
So what exactly is the use case for TryEnterCriticalSection?
I've Googled this, of course. I've found plenty of quick descriptions on how to use it but almost no real-world examples of why. I did find this example from Intel that, frankly doesn't help much:
CRITICAL_SECTION cs;
void threadfoo()
{
while(TryEnterCriticalSection(&cs) == FALSE)
{
// some useful work
}
// Critical Section of Code
LeaveCriticalSection (&cs);
}
// other work
}
What exactly is a scenario in which I can do "some useful work" while I'm waiting for my lock? I'd love to avoid thread-contention but in my code, by the time I need the critical section, I've already been forced to do all that "useful work" in order to get the values that I'm updating in shared data (for which I need the critical section in the first place).
Does anyone have a real-world example?
As an example you might have multiple threads that each produce a high volume of messages (events of some sort) that all need to go on a shared queue.
Since there's going to be frequent contention on the lock on the shared queue, each thread can have a local queue and then, whenever the TryEnterCriticalSection call succeeds for the current thread, it copies everything it has in its local queue to the shared one and releases the CS again.
In C++11 therestd::lock which employs deadlock-avoidance algorithm.
In C++17 this has been elaborated to std::scoped_lock class.
This algorithm tries to lock on mutexes in one order, and then in another, until succeeds. It takes try_lock to implement this approach.
Having try_lock method in C++ is called Lockable named requirement, whereas mutexes with only lock and unlock are BasicLockable.
So if you build C++ mutex on top of CTRITICAL_SECTION, and you want to implement Lockable, or you'll want to implement lock avoidance directly on CRITICAL_SECTION, you'll need TryEnterCriticalSection
Additionally you can implement timed mutex on TryEnterCriticalSection. You can do few iterations of TryEnterCriticalSection, then call Sleep with increasing delay time, until TryEnterCriticalSection succeeds or deadline has expired. It is not a very good idea though. Really timed mutexes based on user-space WIndows synchronization objects are implemented on SleepConditionVariableSRW, SleepConditionVariableCS or WaitOnAddress.
Because windows CS are recursive TryEnterCriticalSection allows a thread to check whether it already owns a CS without risk of stalling.
Another case would be if you have a thread that occasionally needs to perform some locked work but usually does something else, you could use TryEnterCriticalSection and only perform the locked work if you actually got the lock.

How to track/find out which userdata are GC-ed at certain time?

I've written an app in LuaJIT, using a third-party GUI framework (FFI-based) + some additional custom FFI calls. The app suddenly loses part of its functionality at some point soon after being run, and I'm quite confident it's because of some unpinned objects being GC-ed. I assume they're only referenced from the C world1, so Lua GC thinks they're unreferenced and can free them. The problem is, I don't know which of the numerous userdata are unreferenced (unpinned) on Lua side?
To confirm my theory, I've run the app with GC disabled, via:
collectgarbage 'stop'
and lo, with this line, the app works perfectly well long past the point where it got broken before. Obviously, it's an ugly workaround, and I'd much prefer to have the GC enabled, and the app still working correctly...
I want to find out which unpinned object (userdata, I assume) gets GCed, so I can pin it properly on Lua side, to prevent it being GCed prematurely. Thus, my question is:
(How) can I track which userdata objects got collected when my app loses functionality?
One problem is, that AFAIK, the LuaJIT FFI already assigns custom __gc handlers, so I cannot add my own, as there can be only one per object. And anyway, the framework is too big for me to try adding __gc in each and every imaginable place in it. Also, I've already eliminated the "most obviously suspected" places in the code, by removing local from some variables — thus making them part of _G, so I assume not GC-able. (Or is that not enough?)
1 Specifically, WinAPI.
For now, I've added some ffi.gc() handlers to some of my objects (printing some easily visible ALL-CAPS messages), then added some eager collectgarbage() calls to try triggering the issue as soon as possible:
ffi.gc(foo, function()
print '\n\nGC FOO !!!\n\n'
end)
[...]
collectgarbage()
And indeed, this exposed some GCing I didn't expect. Specifically, it led me to discover a note in luajit's FFI docs, which is most certainly relevant in my case:
Please note that [C] pointers [...] are not followed by the garbage collector. So e.g. if you assign a cdata array to a pointer, you must keep the cdata object holding the array alive [in Lua] as long as the pointer is still in use.

Should I delete QSensorReading after using it?

I am trying to use QSensor and friends in Qt5.5 for the first time, and a question has come up; who is responsible for managing instances of QSensorReading? I have tried to understand this by reading the documentation without getting any wiser.
Example:
QAccelerometer *accelerometer=new QAccelerometer(this);
if(accelerometer->connectToBackend()){
accelerometer->start();
}
//Some time later in handler for QSensorReading::readingChanged()signal:
QAccelerometerReading *myReading=accelerometer->reading();
What can I do with myReading here? Should I delete it? Will it be automaticaly delted? Can I pass it safely along as a parameter? Do I risk it being updated (mutable)? Can I copy it somehow?
It's owned by the QSensorBackend, so it'll be deleted with it. The pointer can be passed, but the object doesn't look like copyable. The value inside may be updated (but it's thread safe if it's used in the same thread where the backend lives). The pointer stays the same.

How can I tell whether it's safe/necessary to cudaFree() or not?

I've allocated some GPU global memory with cudaMalloc(), say, in the constructor of some class. Now it's time to destruct the instance I've constructed, and I have my instance's data pointer. The thing is, I'm worried maybe some mischievous code elsewhere has called cudaDeviceReset(), after which my cudaFree() will probably fail (I'll get an invalid device pointer error). So, how can can I tell whether my pointer is elligible for cudaFree()ing?
I don't believe you can do much about that.
About the best you can do is try and engineer the lifespan of objects which will call the CUDA APIs in their destructors to do so before context destruction. In practice, that means having them fall of of scope in a well defined fashion before the context is automatically or manually torn down.
For a call like cudaFree(), which is somewhat "fire and forget" anyway, the best thing to do might be to write your own wrapper for the call and explicitly catch and tastefully ignore any obvious error conditions which would arise if the call was made after context destruction-
Given what talonmies says, one might consider doing the converse:
wrap your cudaDeviceReset() calls to also regard a 'generation counter'.
Counter increases will be protected by a lock.
While you lock, you reset and increment the generation counter.
Wrap cudaMalloc() to also keep the generation index (you might need a class/struct for that) - obtained during allocation (which also locks).
Wrap cudaFree() to lock and only really cudaFree() if the reset generation has not changed.
... now, you might say "Is all that locking worth it? At worst, you'll get an error, it's not such a big deal." And, to be honest - I'm not sure it's worth it. You could make this somewhat less painful by using a Reader-Writer lock instead of a simple lock, where the allocate and free are just readers that can all access concurrently.

Is it a good idea to use the existence of a named mutex as an indicator?

I'm using a named mutex to detect other instances of my application and exit accordingly, and found that there are two ways of doing this:
Create the mutex; ignore the indication whether it already existed; try to acquire it; use the fact that acquire succeeded/failed.
Create the mutex; use the indication whether it already existed.
I can't decide whether to acquire the mutex (and release on exit). On the one hand, acquiring+releasing even though it makes no known difference looks like cargo culting, but on the other hand the existence of a mutex object sounds like a side-effect of its actual intended functionality.
So, should I do #1 or #2 to detect if the app is already running?
The indication that the mutex already existed is sufficient to let you know that there is at least one other process. There is no need to take the mutex for that.
But as long as you have the mutex, you can take it if you need to lock other instances out of some piece of code.
For instance, you can take the mutex until you get out of your initialization code. That way only one instance of your program can be in initialization at a time. If you take the mutex after opening it, the one that got the mutex first knows that no other instance is in its init code. But more importantly, the one that didn't create the mutex knows that the one that create is has finished initialization.
That way if instance 2 wants to talk to instance 1, it knows that instance 1 is ready to listen once it has been able to enter the mutex at least once. This works better if you create the mutex as initially signalled to be absolutely sure that the creator gets to be the first owner.
I'm not sure of it but the named mutex may still exists if the program crashes and doesn't terminate properly. If so, the existence test will succeed whereas no other instance were running. Thus, I personnaly would prefer to try to acquire it ;-)
#1 sounds the way you should go.
Create the mutex; ignore the indication whether it already existed; try to acquire it; use the fact that acquire succeeded/failed
Because your app launching code might be executed twice (on a resume or similar OS stuff), and the acquire will succeed even if the mutex is already existing as it was created by the same app id.

Resources