An example output:
$ ./lsfd -p
3101482 -Q '(FD > 2)'
COMMAND PID USER ASSOC XMODE TYPE SOURCE MNTID INODE NAME
test_mkfds
3101482 yamato 3 rw---- eventpoll anon_inodefs 15 106 tfds=4,5
test_mkfds
3101482 yamato 4 r----m CHR mem:8 23 8 /dev/random
test_mkfds
3101482 yamato 5 -w---m CHR mem:8 23 8 /dev/random
The fd 4 and 5 is multiplexed by 3, an evetpoll fd.
Therefore 'm' flags in XMODE column for fd 4 and 5 are set.
Just one character but 'm' may help users to understand the "IO structure"
of a process.
Signed-off-by: Masatake YAMATO <yamato@redhat.com>
char L = file->locked.write? 'L'
:file->locked.read? 'l'
: '-';
+ char m = file->multiplexed? 'm': '-';
if (does_file_has_fdinfo_alike(file)) {
r = file->mode & S_IRUSR? 'r': '-';
&& file->mode & S_IXUSR)? 'x': '-';
} else
r = w = x = '-';
- xasprintf(&str, "%c%c%c%c%c", r, w, x, D, L);
+ xasprintf(&str, "%c%c%c%c%c%c", r, w, x, D, L, m);
break;
}
case COL_POS:
struct anon_eventpoll_data {
size_t count;
int *tfds;
+ struct list_head siblings;
};
static bool anon_eventpoll_probe(const char *str)
static void anon_eventpoll_init(struct unkn *unkn)
{
- unkn->anon_data = xcalloc(1, sizeof(struct anon_eventpoll_data));
+ struct anon_eventpoll_data *data = xcalloc(1, sizeof(struct anon_eventpoll_data));
+ INIT_LIST_HEAD(&data->siblings);
+ unkn->anon_data = data;
}
static void anon_eventpoll_free(struct unkn *unkn)
struct anon_eventpoll_data *data = (struct anon_eventpoll_data *)unkn->anon_data;
qsort(data->tfds, data->count, sizeof(data->tfds[0]),
intcmp);
+ if (data->count > 0)
+ list_add_tail(&data->siblings,
+ &unkn->file.proc->eventpolls);
}
static char *anon_eventpoll_make_tfds_string(struct anon_eventpoll_data *data,
.attach_xinfo = anon_eventpoll_attach_xinfo,
};
+static int numcomp(const void *a, const void *b)
+{
+ return *(int *)a - *(int *)b;
+}
+
+bool is_multiplexed_by_eventpoll(int fd, struct list_head *eventpolls)
+{
+ struct list_head *t;
+ list_for_each (t, eventpolls) {
+ struct anon_eventpoll_data *data = list_entry(t, struct anon_eventpoll_data, siblings);
+ if (data->count) {
+ if (bsearch(&fd, data->tfds,
+ data->count, sizeof (data->tfds[0]),
+ numcomp))
+ return true;
+ }
+ }
+ return false;
+}
+
/*
* timerfd
*/
_L_ represents a write or an exclusive lock or a write lease. If both
read/shared and write/exclusive locks or leases are taken by a file
descriptor, _L_ is used as the flag.
++
+[-m]:::
+Multiplexed. If the file descriptor is targeted by a eventpoll file,
+this bit flag is set.
== FILTER EXPRESSION
INIT_LIST_HEAD(&proc->files);
INIT_LIST_HEAD(&proc->procs);
+ INIT_LIST_HEAD(&proc->eventpolls);
proc->kthread = 0;
return proc;
}
}
+static void set_multiplexed_flags(struct list_head *procs)
+{
+ struct list_head *p;
+ list_for_each (p, procs) {
+ struct proc *proc = list_entry(p, struct proc, procs);
+ struct list_head *f;
+ list_for_each (f, &proc->files) {
+ struct file *file = list_entry(f, struct file, files);
+ if (is_opened_file(file) && !file->multiplexed) {
+ int fd = file->association;
+ if (is_multiplexed_by_eventpoll(fd, &proc->eventpolls))
+ file->multiplexed = 1;
+ }
+ }
+ }
+}
+
/* Filter expressions for implementing -i option.
*
* To list up the protocol names, use the following command line
free(pids);
attach_xinfos(&ctl.procs);
+ if (scols_table_get_column_by_name(ctl.tb, "XMODE"))
+ set_multiplexed_flags(&ctl.procs);
+
convert(&ctl.procs, &ctl);
struct list_head procs;
struct list_head files;
unsigned int kthread: 1;
+ struct list_head eventpolls;
};
struct proc *get_proc(pid_t pid);
struct {
uint8_t read:1, write:1;
} locked;
+ uint8_t multiplexed;
};
#define is_opened_file(_f) ((_f)->association >= 0)
/* 0 is assumed as the major dev for DEV. */
bool is_mqueue_dev(dev_t dev);
+/*
+ * Eventpoll
+ */
+bool is_multiplexed_by_eventpoll(int fd, struct list_head *eventpolls);
+
#endif /* UTIL_LINUX_LSFD_H */