This is the mail archive of the gdb-patches@sources.redhat.com mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

Re: [RFC] MERGEPID macro wrong ?


On May 30,  9:45am, Pierre Muller wrote:

> At 20:49 29/05/01 , Kevin Buettner a écrit:
> >... I think it would be better to change the MERGEPID define to read
> >as follows:
> >
> >#define MERGEPID(PID,LWP) ptid_build(PID, LWP, 0)
> >
> >Now that we have ptid_t with separate pid, tid, and lwp components we
> >should able to clean up a lot of code which used to overload PIDs, LWPs
> >and TIDs onto an int.
> 
> I think that would be indeed nicer,
> because when you do a grep MERGEPID * in gdb dir you get the following:
> 
> defs.h:/* Provide default definitions of PIDGET, TIDGET, and MERGEPID.
> defs.h:#define MERGEPID(PID, TID) ptid_build (PID, TID, 0)
> gnu-nat.c:           proc->inf->pid, pid_to_thread_id (MERGEPID (proc->tid, 
> 0)));

The gnu-nat.c use of MERGEPID is a recent addition.  I didn't comment on
it at the time, but for this sort of thing I prefer

    pid_to_ptid (proc->tid)

instead of

    MERGEPID (proc->tid, 0)

.  It turns out that these expressions do the same thing.  The reason
I prefer using pid_to_ptid in this case is because (IMHO) it's much
more obvious what's going on.  Also, invoking MERGEPID where the second
argument is explicitly zero implies that the code in question knows
something about what zero means in this context.  (I think that
knowledge should be elsewhere.)

> lynx-nat.c:       inferior_ptid = MERGEPID (PIDGET (inferior_ptid), thread);

Unfortunately, I don't know enough about LynxOS to comment on this one.  I
will point out however, that the ``thread'' argument is obtained from
the status argument passed to wait().

> proc-service.c:#define BUILD_LWP(tid, pid)      MERGEPID (pid, tid)

In this case, the ``tid'' parameter refers to an lwp id.

> procfs.c:  return MERGEPID (pi->pid, proc_get_current_thread (pi));
> procfs.c:             retval = MERGEPID (pi->pid, proc_get_current_thread 
> (pi));
> procfs.c:                   temp_ptid = MERGEPID (pi->pid, temp_tid);
> procfs.c:                   temp_ptid = MERGEPID (pi->pid, temp_tid);
> procfs.c:  inferior_ptid = MERGEPID (pi->pid, proc_get_current_thread (pi));
> procfs.c:  ptid_t gdb_threadid = MERGEPID (pi->pid, thread->tid);

In each of the above uses in procfs.c, the second argument to MERGEPID
is also an lwp id.

> As the distinction between tid and lwp is still rather obsucre to me,

In some settings tids and lwps are identical.  In others, threads are
implemented over lwps (kernel threads) in which there may be multiple
threads per lwp.  It's also possible that there are a pool of lwps to
which threads are allocated.  (Which implies that threads could
migrate from one lwp to another depending upon the whims of the thread
library.)  In any event, I usually think of a tid as something
associated with a user space thread library and an lwp as something
associated with the kernel implemented facilities over which the user
space thread library is implemented.  The book "Unix Internals: The
New Frontiers" by Uresh Vahalla has a very nice treatment of the matter.

> I am just wondering if all the above uses of  MERGEPID
> are completely aware of this subtility!
> The BUILD_LWP macro seems to be a nice example showing that.
> 
>    Coming back to the ptid_t structure,
> I still wonder how threads and processes are handled...

Until recently, a tid and an lwp id occupied the same set of bits and
used a one bit flag to distinguish between the two.  When I added
struct ptid, I decided that it would be better to use a different set
of bits for the lwp id and the tid.  I don't think there's any code in
gdb which actually makes use of this yet, but it seems to me that
some of GDB's thread related code could be cleaned up if it were to
make use of both of these fields simultaneously.  E.g, in
thread-db.c, there are quite a few calls to thread_from_lwp() and
lwp_from_thread().  I believe that most of these exist because
previously it was not possible to simultaneously store both the thread
id and lwp id in the same identifier.  It seems to me that a lot of
code could be greatly simplified if we were to attempt to fully make
use of the fact that it is now possible to store both the tid and lwp
in a ptid_t.

E.g, here's what thread_db_resume() from thread-db.c looks like:

static void
thread_db_resume (ptid_t ptid, int step, enum target_signal signo)
{
  struct cleanup *old_chain = save_inferior_ptid ();

  if (GET_PID (ptid) == -1)
    inferior_ptid = lwp_from_thread (inferior_ptid);
  else if (is_thread (ptid))
    ptid = lwp_from_thread (ptid);

  target_beneath->to_resume (ptid, step, signo);

  do_cleanups (old_chain);
}

This function starts off by invoking the cleanup machinery since
it is possible that thread_db_resume() modifies inferior_ptid:

  struct cleanup *old_chain = save_inferior_ptid ();

It then checks for a magic -1 value that is supposed to indicate that
all threads should be resumed.  Apparently though, this -1 value also
indicates to the lower level that the current inferior should be
treated specially.  (See lin_lwp_resume() in lin-lwp.c.)  Therefore,
it needs to convert inferior_ptid to something that the code in
lin-lwp.c can operate on.  To do so, it invokes lwp_from_thread():

  if (GET_PID (ptid) == -1)
    inferior_ptid = lwp_from_thread (inferior_ptid);

If ptid didn't have the magic -1 pid component, it indicates that
just that thread should be resumed.  But again, ptid might refer
to a thread instead of an lwp.  So again, inferior_ptid needs to
be suitably adjusted so that it may be used by the lwp layer:

  else if (is_thread (ptid))
    ptid = lwp_from_thread (ptid);

Next, the real work of invoking the lwp layer takes place:

  target_beneath->to_resume (ptid, step, signo);

Finally, the original value of inferior_ptid is restored:

  do_cleanups (old_chain);

So... all but one of the above statements are involved with massaging
a ptid into a form that can be used by the lwp layer.  Now that
ptid_t has separate lwp and tid components, this is a very silly
thing to do.  Assuming that ptids were created with both of these
components set correctly, thread_db_resume() could be rewritten as
follows:

static void
thread_db_resume (ptid_t ptid, int step, enum target_signal signo)
{
  target_beneath->to_resume (ptid, step, signo);
}

>    Looking for instance in the win32-nat.c code, I see
> that each thread is considered as a different process, why ??

Someone else will have to answer this...

Kevin


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]