[Toybox] Simplifying (was Re: top -H segfault)

Rob Landley rob at landley.net
Mon Jun 6 12:41:22 PDT 2016


Too much chatter, let me simplify. (Patch inlined below.)

On 06/04/2016 04:46 PM, Rob Landley wrote:
> On 06/04/2016 11:08 AM, enh wrote:
>> sorry, been busy/out but finally got chance to look at this.
> 
> I've been a bit distracted recently too, $DAYJOB's is having a Cash Flow
> Thing and I was a contractor, so I'm job hunting again.

I'm technically unemployed for the moment so should have some time to
work on backlog stuff, including toybox.

>> TNAME seems broken in a couple of ways. it's empty for kernel threads
> 
> Ok, so:
> 
>   For normal processes, show argv[] skipping initial path.
>   For threads, show thread parent's argv[] -path.
>   For _kernel_ threads, show stat[2].
...
> I checked in a thing,

Let me know if that (in current git) is now displaying what you want.

> Right now we have ARGS, CMD, CMDLINE, COMM, COMMAND, NAME, and TNAME,
> all showing slightly different info from three sources (stat[2], args[],
> and /proc/self/exe)

The reason for so many names is that posix is crazy, but I have to
build on top of posix instead of coming up with my own fields.

Posix defines -o cmd,comm,args,command but is very vague about their
meaning. I added -o name,tname. The big problem is all those fields
put together are just a tiny subset of the data we CAN show, which is:

>   1) /proc/$PID/exe
>   2) argv[0]
>   3) stat[2]
>   4) argv[all]
>   5) a way of requesting path truncation on any of the above.
>   6) a way to show thread parent's version of any of the above.

The reason they're different is:

> Everything always has stat[2], although it may be modified for threads.
> argv[] can be overwritten by the process at will. /proc/self/exe is
> immutable but only seems to show up for processes (not threads).

Even if I did invent new syntax this would never be entirely generic
because the thread parent data (#6) has to be copied from the parent
(due to object lifetime rules), and copying EVERYTHING is expensive.

Plus I'd need a (7) saying "when this is blank, fall back to that",
since "fall back to stat[2]" isn't universal enough.

So please tell me what behavior you need in terms of the data sources
and the fallback sequence.

>> all the pieces to replace Android's old top. TNAME gives me what we've
>> historically called the "process name" and COMM gives me what we've
>> called the "thread name".

Should I rename "TNAME" to "PNAME"? Or just change the behavior of
"NAME" to do this instead?

>>  1939  1939 root     20   0  0.0 S      0     0  fg
>>          kworker/0:3
> 
> You're showing me what it _is_ doing, not what you want. Let me try to
> guess what you want.
> 
> In this case pid==tid, so... you want TNAME to show argv[0] of the
> current process in that case? Maybe?
> 
> Something like the attached patch, maybe?

Here is the patch making a second guess at what you want. It's on
top of current git (the above "is this what you want"), and changes
the TNAME behavior to "Show parent argv[0]. If that's blank, show
our argv[0]. If that's blank, show [stat2]."

That way threads show their parents, parents show themselves, and
kernel threads show the [stat2] name. Is this what you want?

diff --git a/toys/posix/ps.c b/toys/posix/ps.c
index 82a8443..879ebfd 100644
--- a/toys/posix/ps.c
+++ b/toys/posix/ps.c
@@ -443,13 +443,24 @@ static char *string_field(struct carveup *tb, struct strawberry *field)
     sl *= -1;
     // First string slot has offset 0, others are offset[-slot-2]
     if (--sl) out += tb->offset[--sl];
+    // If TNAME is blank, show ARGS instead
+    if (which==PS_ARGS && !*out)
+      out = tb->str+tb->offset[-2-typos[which = PS_ARGS].slot];
     if (which==PS_ARGS || which==PS_NAME) {
-      int i;
+      int i, j;
 
       s = out;
       for (i = 0; (which==PS_ARGS) ? i < slot[SLOT_argv0len] : out[i]; i++)
         if (out[i] == '/') s = out+i+1;
+      i = s - out;
       out = s;
+      if (which != field->which) {
+        j = slot[SLOT_argv0len]-i;
+        if (j > 259) j = 259;
+        memcpy(buf, out+i, j);
+        buf[j] = 0;
+        out = buf;
+      }
     }
     if (which>=PS_COMM && !*out) sprintf(out = buf, "[%s]", tb->str);
 

[Deleted explanation of ps object lifetime rules, and explaining why
your patch didn't do what you thought it did.]

Here is a third option I can implement:

> In a previous message you said a process can write data to argv[0] after
> forking but before spawning threads, and that this was information you
> needed to know. So I switched to snapshotting that instead.
> 
> If I need to snapshot _both_ fields out of the parent, I can do that.
> But that's adding a slot[7], not redefining slot[6] again.

[Deleted explanation of why layered testing doesn't catch
code moving between layers, and why testing old assumptions
doesn't help when the problem is that the design changed.]

[Deleted yet another way of saying writing code is easy and
figuring out what to do is hard.]

Rob


More information about the Toybox mailing list