Re: How to check whether executing in atomic context?

From: Leonidas .
Date: Wed Oct 14 2009 - 15:12:58 EST


On Wed, Oct 14, 2009 at 11:09 PM, Stefan Richter
<stefanr@xxxxxxxxxxxxxxxxx> wrote:
> On 10/14/2009 12:24 PM, Leonidas . wrote:
>> On Wed, Oct 14, 2009 at 3:13 AM, Gleb Natapov <gleb@xxxxxxxxxx> wrote:
>>> On Wed, Oct 14, 2009 at 02:21:22AM -0700, Leonidas . wrote:
>>>> On Tue, Oct 13, 2009 at 11:36 PM, Leonidas . <leonidas137@xxxxxxxxx> wrote:
>>>> > Hi List,
>>>> >
>>>> > I am working on a profiler kind of module, the exported apis of my module can be
>>>> > called from process context and interrupt context as well. Depending on the
>>>> > context I am called in, I need to call sleepable/nonsleepable variants
>>>> > of my internal bookkeeping functions.
>>>> >
>>>> > I am aware of in_interrupt() call which can be used to check current
>>>> > context and take action accordingly.
>>>> >
>>>> > Is there any api which can help figure out whether we are executing while hold a spinlock? I.e
>>>> > an api which can help figure out sleepable/nonsleepable context? If it is not there, what can
>>>> > be done for writing the same? Any pointers will be helpful.
> [...]
>>>>   While searching through the sources, I found this,
>>>>
>>>>   97/*
>>>>   98 * Are we running in atomic context?  WARNING: this macro cannot
>>>>   99 * always detect atomic context; in particular, it cannot know about
>>>>  100 * held spinlocks in non-preemptible kernels.  Thus it should not be
>>>>  101 * used in the general case to determine whether sleeping is possible.
>>>>  102 * Do not use in_atomic() in driver code.
>>>>  103 */
>>>>  104#define in_atomic()     ((preempt_count() & ~PREEMPT_ACTIVE) != PREEMPT_INATOMIC_BASE)
>>>>  105
>>>>
>>>> this just complicates the matter, right? This does not work in general case but I think this
>>>> will always work if the kernel is preemptible.
>>>>
>>>> Is there no way to write a generic macro?
> [...]
>>> Attached patch make in_atomic() to work for non-preemptable kernels too.
>>> Doesn't look to big or scary.
>>>
>>> Disclaimer: tested only inside kvm guest 64bit, haven't measured overhead.
> [...]
>> Unbelievable! I was just thinking about the logic to achieve the same, and
>> someone has already done this. Thanks for the patch.
>
> I don't know whether Gleb's patch works or doesn't work as you require
> it.  But my opinion is that the recommendation "do not use in_atomic()
> in driver code" is valid nevertheless.
>
> Very often the better course of action is to change your API from
>
> void my_routine()
> {
>        if (in_atomic())
>                this;
>        else
>                that;
> }
>
> to either
>
> void my_routine(bool can_sleep)
> {
>        if (!can_sleep)
>                this;
>        else
>                that;
> }
>
> or to
>
> void my_routine_atomic()
> {
>        this;
> }
>
> void my_routine()
> {
>        that;
> }
>
> In other words, let the caller of your routine tell it whether it's
> atomic context or not.
>
> Instead of a "bool can_sleep" argument, a "gfp_t flags" argument is
> often used.
>
> Or provide only the my_routine_atomic() variant if the difference to the
> sleeping variant isn't huge.
> --
> Stefan Richter
> -=====-==--= =-=- -===-
> http://arcgraph.de/sr/
>


I agree with you and earlier consensus on list about the atomic and
non-atomic variants.

The issue with my code, as I have explained briefly earlier in the
same thread is as
follows:

My apis can be inserted at any place in this code by user. I have no
control over this
part except telling user to call atomic/non-atomic apis depending on
the context.

What makes it more complicated is this, the user might achieve the
functionality via instrumenting his source code, i.e. something like
using -finstrument flag of gcc. As per above inferences about
in_atomic(), in case of instrumentation there is no choice other than
providing all apis as atomic apis, this might not be the right thing
to do under all circumstances. Especially, for my code since I do lot
of allocations for book keeping.

I am not aware of any Linux kernel module which can comply to this
kind of use case, what would be the most optimal thing to do here?

-Leo.
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/