0

This is my solution so far:

int is_descendant(task_t* ansc, task_t* targ)
{
    task_t* p_tmp;
    for(p_tmp = targ ; (p_tmp) && (ansc) && (p_tmp->pid) && (p_tmp->pid != ansc->pid) ; p_tmp = p_tmp->p_pptr) ; 
    if((!p_tmp) || (!current) || (!p_tmp->pid)) return -ESRCH;
    return 0;
}

It works but I'm unsure about several things:

  1. without checking if p_tmp->pid == 0 it iterates forever, does that mean that the parent pointer of the first process is not NULL ?

  2. is it necessary to check if p_tmp or ansc are NULL ?

  3. is there a better way to do this ? (using O(1) space compl.)

  4. macro vs. function ?

    Thanks

Community
  • 1
  • 1
userfault
  • 199
  • 1
  • 10
  • What is `task_t` type? There is no such type in modern Linux kernel. If you mean `task_struct` object, then it has `.parent` field denoted parent of this task. – Tsyvarev Oct 19 '16 at 12:24
  • i'm on kernel 2.4, `task_t` is defined as `typedef struct task_struct task_t` – userfault Oct 19 '16 at 12:28

2 Answers2

0

As for 4.: What are you hoping to get by using a macro instead of a function? It is almost always better to use a function and to not use a macro.

The basic problems with macros include (but are not necessarily limited to) the following:

  • Macros are error-prone, because they use text substitution. They might not always do what you expect them to do, and to find these errors is not always trivial.
  • Macros can cause unwanted side effects like evaluating an expression multiple times.
  • Macros cannot return a value as in your return NOTDESCENDANT line. (It might work, if the macro is used inside of a function that has a matching return type.)
  • Writing (and possibly also reading) macros that span multiple lines is a pain.

All these points are also discussed here: Macro vs Function in C You can also see some examples for all these problems there.

Bottom line: When in doubt, always use functions or inline functions instead of macros.

Community
  • 1
  • 1
Striezel
  • 3,693
  • 7
  • 23
  • 37
  • Thanks, I applied this practice and edited my original question. as a matter of fact, I've seen many macros in the kernel and assumed it was some kind of convention when coding for the kernel. still hoping to get an answer for the other questions though. – userfault Oct 18 '16 at 21:59
0

does that mean that the parent pointer of the first process is not NULL ?

According to sources, parent for the init task is this task itself.

is it necessary to check if p_tmp or ansc are NULL ?

Parent task (->p_pptr) cannot be NULL, so p_tmp cannot be NULL too.

ansc is a parameter of the function which isn't modified within the function body. Whether function should accept NULL or not is up to design.

is there a better way to do this ? (using O(1) space compl.)

As task stores pointers neither to all its ancestors nor to all its descendants, you cannot perform operation at constant time (O(1)).

int is_descendant(task_t* ansc, task_t* targ)
{
    task_t* p_tmp;
    if(ansc->pid == 0) return 0; // init task is ansestor for all tasks.
    for(p_tmp = targ; p_tmp->pid; p_tmp = p_tmp->p_pptr)
        if(p_tmp == ansc) return 0; // Found path to 'ansc'
    // Reach init task without touching 'ansc'.
    return 1;
}
Tsyvarev
  • 60,011
  • 17
  • 110
  • 153