Hi Jim, Jim Meyering <[email protected]> writes:
> Thanks for the suggestion. > Yes, this has been discussed, e.g., in > > http://thread.gmane.org/gmane.comp.gnu.coreutils.bugs/15031/focus=15052 > > I like the idea and outlined how I'd like to see this functionality > make it's way into the coreutils. I read this discussion but looking at the tail source code I didn't see any difficulty to use inotify. These are some tests results: test -e /tmp/files || mkdir /tmp/files; for i in $(seq 2000); do touch /tmp/files/$i; done my version: ./timeout -sINT 30s env time ./tail -f /tmp/files/* 0.02user 0.09system 0:30.00elapsed 0%CPU (0avgtext+0avgdata 0maxresident)k 0inputs+0outputs (0major+232minor)pagefaults 0swaps system version: ./timeout -sINT 30s env time tail -f /tmp/files/* 0.05user 0.16system 0:29.99elapsed 0%CPU (0avgtext+0avgdata 0maxresident)k 0inputs+0outputs (0major+236minor)pagefaults 0swaps I am sure running the test for a longer time would give better results. The initial time using inotify is higher as there is need to create watch descriptors and an index I use for access to the File_spec in costant time. What do you think of the attached patch? Cheers, Giuseppe >From aa815abdd3cbf2ad15d769a1f4cb6100e3a975e5 Mon Sep 17 00:00:00 2001 From: Giuseppe Scrivano <[email protected]> Date: Sat, 30 May 2009 13:31:58 +0200 Subject: [PATCH] tail: Use inotify if it is available. * NEWS: Document the new feature * configure.ac: Check if inotify is present. * src/tail.c (main): Use the tail_forever inotify version if it is possible. (tail_forever_inotify): Added new function. --- NEWS | 2 + configure.ac | 2 + src/tail.c | 103 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 105 insertions(+), 2 deletions(-) diff --git a/NEWS b/NEWS index 29b09a0..c5a2ef5 100644 --- a/NEWS +++ b/NEWS @@ -14,6 +14,8 @@ GNU coreutils NEWS -*- outline -*- sort accepts a new option, --human-numeric-sort (-h): sort numbers while honoring human readable suffixes like KiB and MB etc. + tail uses inotify if it is present. + * Noteworthy changes in release 7.4 (2009-05-07) [stable] diff --git a/configure.ac b/configure.ac index 4eb640e..a63ac0c 100644 --- a/configure.ac +++ b/configure.ac @@ -410,6 +410,8 @@ AM_GNU_GETTEXT_VERSION([0.15]) # For a test of uniq: it uses the $LOCALE_FR envvar. gt_LOCALE_FR +AC_CHECK_FUNCS([inotify_init], [AC_DEFINE([HAVE_INOTIFY], [1], [Check for libinotify])]) + AC_CONFIG_FILES( Makefile doc/Makefile diff --git a/src/tail.c b/src/tail.c index fe34600..bb0950e 100644 --- a/src/tail.c +++ b/src/tail.c @@ -1,5 +1,5 @@ /* tail -- output the last part of file(s) - Copyright (C) 1989, 90, 91, 1995-2006, 2008 Free Software Foundation, Inc. + Copyright (C) 1989, 90, 91, 1995-2006, 2008, 2009 Free Software Foundation, Inc. This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -45,6 +45,10 @@ #include "xstrtol.h" #include "xstrtod.h" +#ifdef HAVE_INOTIFY +#include <sys/inotify.h> +#endif + /* The official name of this program (e.g., no `g' prefix). */ #define PROGRAM_NAME "tail" @@ -1116,6 +1120,93 @@ tail_forever (struct File_spec *f, int nfiles, double sleep_interval) } } +#ifdef HAVE_INOTIFY +/* Tail NFILES files forever, or until killed. + Check modifications using the inotify events system. */ +static void +tail_forever_inotify (int wd, struct File_spec *f, int nfiles) +{ + /* Create an index to access File_spec by its watch descriptor + * in costant time. */ + struct File_spec **wd_index; + int i; + int *watch_fd = xmalloc (sizeof (int) * nfiles); + int min_wd = -1; + int max_wd = -1; + int watched = 0; + size_t last; + + for (i = 0; i < nfiles; i++) + { + watch_fd[i] = -1; + + if (!f[i].ignore) + { + watch_fd[i] = inotify_add_watch (wd, f[i].name, + IN_MODIFY); + + if (watch_fd[i] < 0) + { + error (0, errno, _("cannot watch %s"), quote (f[i].name)); + continue; + } + + watched++; + + if (watch_fd[i] > max_wd || max_wd < 0) + max_wd = watch_fd[i]; + + if (watch_fd[i] < min_wd || min_wd < 0) + min_wd = watch_fd[i]; + } + } + + if (!watched) + return; + + wd_index = xmalloc (sizeof (struct File_spec**) * (max_wd - min_wd + 1)); + + for (i = 0; i < nfiles; i++) + if (watch_fd[i] > 0) + wd_index[watch_fd[i] - min_wd] = &(f[i]); + + free (watch_fd); + + last = max_wd + 1; + + while (1) + { + size_t len; + struct inotify_event ev; + char const *name; + struct File_spec *fspec; + uintmax_t bytes_read; + + len = read (wd, &ev, sizeof (struct inotify_event)); + if (!len && errno == EINTR) + continue; + + if (!len) + error (EXIT_FAILURE, errno, _("error reading inotify event")); + + fspec = wd_index [ev.wd - min_wd]; + + name = pretty_name (fspec); + + if (ev.wd != last) + { + if (print_headers) + write_header (name); + last = ev.wd; + } + + bytes_read = dump_remainder (name, fspec->fd, COPY_TO_EOF); + fspec->size += bytes_read; + } + +} +#endif + /* Output the last N_BYTES bytes of file FILENAME open for reading in FD. Return true if successful. */ @@ -1690,7 +1781,15 @@ main (int argc, char **argv) ok &= tail_file (&F[i], n_units); if (forever) - tail_forever (F, n_files, sleep_interval); + { +#ifdef HAVE_INOTIFY + int wd = inotify_init (); + + if (wd > 0) + tail_forever_inotify (wd, F, n_files); +#endif + tail_forever (F, n_files, sleep_interval); + } if (have_read_stdin && close (STDIN_FILENO) < 0) error (EXIT_FAILURE, errno, "-"); -- 1.6.3.1 _______________________________________________ Bug-coreutils mailing list [email protected] http://lists.gnu.org/mailman/listinfo/bug-coreutils
