Compiling for 10-year old Linux kernels...

89 views
Skip to first unread message

Joseph Van Riper

unread,
Jun 19, 2019, 8:28:31 AM6/19/19
to libuv
CMake uses this library for some of its work, but it doesn't compile on Linux kernels previous to 2.6.27 thanks to a missing epoll_create1 function introduced in 2.6.26.

I can provide an update that would address this by using preprocessor directives to test the kernel version and appropriately use epoll_create or epoll_create1, but in testing, I still see five tests failing (within my use case):

not ok 48 - fs_copyfile
# exit code 134
# Output from process `fs_copyfile`:
# Assertion failed in test/test-fs-copyfile.c on line 126: r == 0

not ok 63 - fs_event_watch_file_twice
# exit code 134
# Output from process `fs_event_watch_file_twice`:
# Assertion failed in test/test-fs-event.c on line 635: 0 == uv_fs_event_start(watchers + 0, fail_cb, path, 0)

not ok 91 - fs_readdir_file
# exit code 134
# Output from process `fs_readdir_file`:
# Assertion failed in test/test-fs-readdir.c on line 244: r == UV_ENOTDIR

not ok 98 - fs_scandir_file
# exit code 134
# Output from process `fs_scandir_file`:
# Assertion failed in test/test-fs.c on line 2541: r == UV_ENOTDIR

not ok 166 - pipe_connect_to_file
# exit code 134
# Output from process `pipe_connect_to_file`:
# Assertion failed in test/test-pipe-connect-error.c on line 53: status == UV_ENOTSOCK || status == UV_ECONNREFUSED


I strongly doubt the changes I made caused these failures, though.   My changes look like this:

#include <linux/version.h>


#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,27)
/* epoll_create1 unavailable in these kernels */
#define NO_EPOLL_CREATE1
#endif
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,8)
/* epoll_create ignores the size parameter in these kernels */
#define EPOLL_IGNORE_SIZE
#endif

(after the other #includes, followed by):

int uv__platform_loop_init(uv_loop_t* loop) {
 
int fd;

#ifndef NO_EPOLL_CREATE1


 
/* It was reported that EPOLL_CLOEXEC is not defined on Android API < 21,
   * a.k.a. Lollipop. Since EPOLL_CLOEXEC is an alias for O_CLOEXEC on all
   * architectures, we just use that instead.
   */

  fd
= epoll_create1(O_CLOEXEC);

#elif defined EPOLL_IGNORE_SIZE

  fd
= epoll_create(1);

#else

  fd
= -1;
  errno
= ENOSYS;

#endif

 
/* epoll_create1() can fail either because it's not implemented (old kernel)
   * or because it doesn't understand the O_CLOEXEC flag.
   */

 
if (fd == -1 && (errno == ENOSYS || errno == EINVAL)) {
    fd
= epoll_create(256);

   
if (fd != -1)
      uv__cloexec
(fd, 1);
 
}

  loop
->backend_fd = fd;
  loop
->inotify_fd = -1;
  loop
->inotify_watchers = NULL;

 
if (fd == -1)
   
return UV__ERR(errno);

 
return 0;
}


I'm hesitant to submit this because of the failures, even though the tests succeed in a normal use case (building for a current Linux OS with normal toolkits).

Recommendations?
 

Ben Noordhuis

unread,
Jun 19, 2019, 8:37:29 AM6/19/19
to li...@googlegroups.com
I agree the test failures are unrelated to your change.

As to the change itself, libuv does feature detection at runtime, not
compile time. Rather than sniffing system headers, it makes the system
call directly (using syscall()) and checks for ENOSYS.

We used to have wrappers for epoll until not too long ago but I
removed those in https://github.com/libuv/libuv/pull/1372 and now
libuv goes through libc. I'd be okay with restoring the wrappers for
epoll_create() and epoll_create1() if that helps out cmake as long as
it's understood that it comes with absolutely no promise of support.

You're welcome to open a pull request. Check the other pull request to
see how to implement it.

Joseph Van Riper

unread,
Jun 19, 2019, 9:52:58 AM6/19/19
to libuv


On Wednesday, June 19, 2019 at 8:37:29 AM UTC-4, Ben Noordhuis wrote:
On Wed, Jun 19, 2019 at 2:28 PM Joseph Van Riper
<vanrip...@gmail.com> wrote:
>
> CMake uses this library for some of its work, but it doesn't compile on Linux kernels previous to 2.6.27 thanks to a missing epoll_create1 function introduced in 2.6.26.
>
> I can provide an update that would address this by using preprocessor directives to test the kernel version and appropriately use epoll_create or epoll_create1, but in testing, I still see five tests failing (within my use case):

[snip] 

I agree the test failures are unrelated to your change.

As to the change itself, libuv does feature detection at runtime, not
compile time. Rather than sniffing system headers, it makes the system
call directly (using syscall()) and checks for ENOSYS.

We used to have wrappers for epoll until not too long ago but I
removed those in https://github.com/libuv/libuv/pull/1372 and now
libuv goes through libc. I'd be okay with restoring the wrappers for
epoll_create() and epoll_create1() if that helps out cmake as long as
it's understood that it comes with absolutely no promise of support.

You're welcome to open a pull request. Check the other pull request to
see how to implement it.

After some more research, I've decided against trying to make this work for this use case.

I found CMake test errors with the current version of CMake while trying to do this with a version of libuv that does not fail libuv's tests.  This means, to get my use case to work correctly, one would not only need to address the issues I found in libuv, but also the ones in CMake.

Ergo, after some thinking about this problem, I've decided upon another approach that shouldn't involve coercing 3rd party modern code to work in ancient environments, yet should still allow me to use these current versions.  This kind of problem is mine, and shouldn't require other projects to conform to my needs (and the inevitable maintenance issues thereafter).

As for the changes I intended to make, they were necessary to get libuv to build.  I had created a docker image with a 2.6.26 linux kernel, then used git to pull libuv.  I found I couldn't compile libuv in this environment without either the compiler or the linker (I forget which) complaining about epoll_create1 missing.  Had I examined the existing code more carefully, I would have noticed it calling epoll_create() anyway when the previous call failed, so I shouldn't have bothered with that EPOLL_IGNORE_SIZE code.

Thank you for your response, and I hope all goes well in your neck of the woods.
Reply all
Reply to author
Forward
0 new messages