[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Re: Python or Perl for a Debian maintainance project?



On Thu, Feb 19, 2004 at 10:42:56AM +0800, Isaac To wrote:
> >>>>> "Andrew" == Andrew Suffield <asuffield@debian.org> writes:
> 
>     Andrew> It does if you do it right. I don't exactly write this sort of
>     Andrew> code infrequently; it's quite easy to structure your code in a
>     Andrew> manner that works neatly and effectively.
> 
> Perhaps you want to enlighten the kernel developers.

Not particularly. I am very unlikely to ever work on that code.

> A typical kernel
> function, say sys_getpgid, is implemented (in 2.4.24 kernel) like this:
> 
> asmlinkage long sys_setpgid(pid_t pid, pid_t pgid)
> {
>         struct task_struct * p;
>         int err = -EINVAL;
> 
>         if (!pid)
>                 pid = current->pid;
>         if (!pgid)
>                 pgid = pid;
>         if (pgid < 0)
>                 return -EINVAL;
> 
>         /* From this point forward we keep holding onto the tasklist lock
>          * so that our parent does not change from under us. -DaveM
>          */
>         read_lock(&tasklist_lock);
> 
>         err = -ESRCH;
>         p = find_task_by_pid(pid);
>         if (!p)
>                 goto out;
> 
>         if (p->p_pptr == current || p->p_opptr == current) {
>                 err = -EPERM;
>                 if (p->session != current->session)
>                         goto out;
>                 err = -EACCES;
>                 if (p->did_exec)
>                         goto out;
>         } else if (p != current)
>                 goto out;
>         err = -EPERM;
>         if (p->leader)
>                 goto out;
>         if (pgid != pid) {
>                 struct task_struct * tmp;
>                 for_each_task (tmp) {
>                         if (tmp->pgrp == pgid &&
>                             tmp->session == current->session)
>                                 goto ok_pgid;
>                 }
>                 goto out;
>         }
> 
> ok_pgid:
>         p->pgrp = pgid;
>         err = 0;
> out:
>         /* All paths lead to here, thus we are safe. -DaveM */
>         read_unlock(&tasklist_lock);
>         return err;
> }

And here's how I'd do it (just fixing this one issue; I wouldn't have
written the rest like this anyway - I'd have used some comments, for
starters):

static long
do_setpgid(pid_t pid, pid_t pgid)
{
        struct task_struct * p;

        p = find_task_by_pid(pid);
        if (!p)
                return -ESRCH;

        if (p->p_pptr == current || p->p_opptr == current) {
                if (p->session != current->session)
                        return -EPERM;
                if (p->did_exec)
                        return -EACCES;
        } else if (p != current)
                return -ESRCH;

        if (p->leader)
                return -EPERM;

        if (pgid != pid) {
                struct task_struct * tmp;
                for_each_task (tmp) {
                        if (tmp->pgrp == pgid &&
                            tmp->session == current->session)
                          {
                            p->pgrp = pgid;
                            return 0;
                          }
                }
                return -EPERM;
        }
}

asmlinkage long sys_setpgid(pid_t pid, pid_t pgid)
{
        long ret;

        if (!pid)
                pid = current->pid;
        if (!pgid)
                pgid = pid;
        if (pgid < 0)
                return -EINVAL;

        read_lock(&tasklist_lock);

        ret = do_setpgid(pid, pgid);

        read_unlock(&tasklist_lock);
        return ret;
}

(The idiom here is: check input, acquire resources, process, release
resources, and split those out into other functions as needed - strict
two-phase locking, which avoids deadlocks into the bargain)

No gotos, no need to worry about the current value of err, and
significant code is cleanly separated from locking and argument
checking. And both functions are rather easier to read (if a function
is too big to fit entirely on screen at once, you probably need to
split it up - the exception is when it's caused by huge comments).

Most problems in computer science are solved by adding another layer
of abstraction.

> For me, if "goto" is used in a disciplined way, one shouldn't be afraid to
> use them, especially if it simplify your code.

It never simplifies code. That's been the whole point for the past
Eris-knows-how-many years. Any time that you think you've found a use
of goto that makes the code simpler, there's another way to write it
without goto that would be simpler still. Example above.

-- 
  .''`.  ** Debian GNU/Linux ** | Andrew Suffield
 : :' :  http://www.debian.org/ |
 `. `'                          |
   `-             -><-          |

Attachment: signature.asc
Description: Digital signature


Reply to: