On this link a return type is defined

return ((unsigned int)(unsigned long)base & TBASE_DEFERRABLE_FLAG);

What is the above function returning.I am not clear with definition of what is being returned in the above code.

Dani AI

Generated

Short answer for : that return expression is testing the lowest bit of the pointer and returning whether that bit is set (so the value will be 0 or 1 in the common case). As discovered, the kernel reuses the pointer's low bit as a small "deferrable" flag because tvec_base objects are guaranteed to be aligned so the real pointer never needs that bit.

Step-by-step, in plain terms:

  • the pointer value is converted to an integer so its raw address bits can be examined,
  • the bitwise & with the flag constant keeps only the bit(s) of interest (if the flag is 0x1 that is the least-significant bit),
  • the result is cast to the function's return type and returned (so the expression yields zero when the flag is clear and non-zero when set).
    Replying to : using 0xFF would test the lower 8 bits, not just the single LSB; that is unnecessary here and could hide intent—0x1 specifically isolates the single lowest bit.

Safer, clearer approach (portable and self-documenting) is to use uintptr_t and small inline helpers so the intent is explicit and truncation/width issues are avoided:

#include <stdint.h>

static inline int tbase_is_deferrable(const struct tvec_base *b)
{
    return ((uintptr_t)b & (uintptr_t)TBASE_DEFERRABLE_FLAG) ? 1 : 0;
}

static inline struct tvec_base *tbase_strip_flag(const struct tvec_base *b)
{
    return (struct tvec_base *)((uintptr_t)b & ~(uintptr_t)TBASE_DEFERRABLE_FLAG);
}

Cautions: pointer tagging only works when alignment guarantees exist (document that invariant), pointer-to-integer casts must use a type guaranteed to hold a pointer (uintptr_t), and multi-threaded or atomic updates to tagged pointers require care. In kernel code this trick is common and efficient; in portable user-space code prefer explicit fields unless tight memory/performance constraints justify tagging.

Recommended Answers

All 7 Replies

To see what's just do some substitution...

#define TBASE_DEFERRABLE_FLAG (0x1)
struct tvec_base *base

First we cast base to unsigned long
(unsigned long)base

Then we perform the bit operation & on
(unsigned long)base & 0x1

Then we cast our result to
(unsigned long)(unsigned long)base & 0x1

Why do it this way? It may be a simple trick to manipulate the spinlock_t variable in

struct tvec_base {
         spinlock_t lock;
         struct timer_list *running_timer;
         unsigned long timer_jiffies;
         struct tvec_root tv1;
         struct tvec tv2;
         struct tvec tv3;
         struct tvec tv4;
         struct tvec tv5;
} ____cacheline_aligned;

Note I said 'may' be a way.

To see what's just do some substitution...

#define TBASE_DEFERRABLE_FLAG (0x1)
struct tvec_base *base

First we cast base to unsigned long
(unsigned long)base

Then we perform the bit operation & on
(unsigned long)base & 0x1

Then we cast our result to
(unsigned long)(unsigned long)base & 0x1

Why do it this way? It may be a simple trick to manipulate the spinlock_t variable in

struct tvec_base {
         spinlock_t lock;
         struct timer_list *running_timer;
         unsigned long timer_jiffies;
         struct tvec_root tv1;
         struct tvec tv2;
         struct tvec tv3;
         struct tvec tv4;
         struct tvec tv5;
} ____cacheline_aligned;

Note I said 'may' be a way.

Adding myself into this thread
Hi Gerard, Can you explain why do you think that it could be for manipulating the lock variable?

Actually I made the reply before coffee...These remarks indicate

/*
085 * Note that all tvec_bases are 2 byte aligned and lower bit of
086 * base in timer_list is guaranteed to be zero. Use the LSB for
087 * the new flag to indicate whether the timer is deferrable
088 */

That your masking out the bit of struct tvec_base *base with 0x1 and returning the value.

Actually I made the reply before coffee...These remarks indicate


That your masking out the bit of struct tvec_base *base with 0x1 and returning the value.

To get the LSB, 0xFF Should be used. Isnt it?

Because its aligned 2 bytes its guaranteed that the address & 0x1 will return 0...Check out the attached code..

#include <stdio.h>
#include <stdlib.h>

int main(int argc, char**argv)
{
	int i = 0;
	char __attribute__((aligned(2))) ch1;
	char *cptr = &ch1;

	for (i = 0; i < 20; ++i)	
	{
		fprintf(stdout, "ans->%u\n", ((unsigned int)(unsigned long)cptr & 0x1));
		cptr += 2;
	}


	exit(EXIT_SUCCESS);
}

The output is ans->0 for all iterations...Why do they have a function that tests for this? I really don't know.

commented: thanks :) +1

Because its aligned 2 bytes its guaranteed that the address & 0x1 will return 0...Check out the attached code..

#include <stdio.h>
#include <stdlib.h>

int main(int argc, char**argv)
{
	int i = 0;
	char __attribute__((aligned(2))) ch1;
	char *cptr = &ch1;

	for (i = 0; i < 20; ++i)	
	{
		fprintf(stdout, "ans->%u\n", ((unsigned int)(unsigned long)cptr & 0x1));
		cptr += 2;
	}


	exit(EXIT_SUCCESS);
}

The output is ans->0 for all iterations...Why do they have a function that tests for this? I really don't know.

Yeah.. I understood what you meant. thanks..
Next question is slightly out of context.. But to finish this discussion off with no questions remain unanswered in my mind,
Do you know what is that new flag that they are talking about in the comment?

I could not understand any thing from your discussion.I am a learning programmer please explain in simple terms.I have programmed in normal C this sort of kernel C is new to me.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.