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.
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.
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:
& with the flag constant keeps only the bit(s) of interest (if the flag is 0x1 that is the least-significant bit),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.
Jump to Post— gerard4143 371To see what's just do some substitution...
#define TBASE_DEFERRABLE_FLAG (0x1)
struct tvec_base *baseFirst we cast base to unsigned long
(unsigned long)baseThen we perform the bit operation & on
(unsigned long)base & 0x1Then we cast our result to
(unsigned long)(unsigned long)base & 0x1…
Jump to Post— gerard4143 371Because 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) …
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 *baseFirst we cast base to unsigned long
(unsigned long)baseThen we perform the bit operation & on
(unsigned long)base & 0x1Then we cast our result to
(unsigned long)(unsigned long)base & 0x1Why 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.
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.
We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.