Skip to content

Linux port hdd timers2 #8

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Dec 12, 2015
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -137,9 +137,14 @@ AC_SEARCH_LIBS(pthread_create, pthread)
# Prefer native kqueue(2); otherwise use libkqueue if present.
#
AC_CHECK_HEADER(sys/event.h, [],
[PKG_CHECK_MODULES(KQUEUE, libkqueue)]
[PKG_CHECK_MODULES(KQUEUE, libkqueue)
AC_SEARCH_LIBS(kevent, kqueue)
AC_SEARCH_LIBS(kevent64, kqueue,
[AC_DEFINE(HAVE_KEVENT64, 1, [Define if kevent64 is present])],
[AC_DEFINE(HAVE_KEVENT64, 0, [Define if kevent64 is present])])]
)


#
# Checks for header files.
#
Expand Down
49 changes: 27 additions & 22 deletions os/linux_base.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#define __OS_LINUX_BASE__

// #include <sys/event.h>
#include <sys/user.h>

// marker for hacks we have made to make progress
#define __LINUX_PORT_HDD__ 1
Expand Down Expand Up @@ -76,34 +77,41 @@ struct voucher_offsets_s {
};


// Print a warning when an unported code path executes.
#define LINUX_PORT_ERROR() do { printf("LINUX_PORT_ERROR_CALLED %s:%d: %s\n",__FILE__,__LINE__,__FUNCTION__); } while (0)

/*
* Stub out defines for other missing types
*/

// Pulled from OS X man page for kevent
struct kevent64_s {
uint64_t ident; /* identifier for this event */
int16_t filter; /* filter for event */
uint16_t flags; /* general flags */
uint32_t fflags; /* filter-specific flags */
int64_t data; /* filter-specific data */
uint64_t udata; /* opaque user data identifier */
uint64_t ext[2]; /* filter-specific extensions */
};

#if !HAVE_KEVENT64
// we fall back to use kevent
#define kevent64_s kevent
#define kevent64(kq,cl,nc,el,ne,f,to) kevent(kq,cl,nc,el,ne,to)
#endif

// PAGE_SIZE and SIZE_T_MAX should not be hardcoded like this here.
#define PAGE_SIZE (4096)
// SIZE_T_MAX should not be hardcoded like this here.
#define SIZE_T_MAX (0x7fffffff)

// Define to 0 the NOTE_ values that are not present on Linux.
// Revisit this...would it be better to ifdef out the uses instead??
#define NOTE_VM_PRESSURE 0
#define NOTE_ABSOLUTE 0
#define NOTE_NSECONDS 0
#define NOTE_LEEWAY 0
#define NOTE_CRITICAL 0
#define NOTE_BACKGROUND 0

// The following values are passed as part of the EVFILT_TIMER requests

#define IGNORE_KEVENT64_EXT /* will force the kevent64_s.ext[] to not be used -> leeway ignored */

#define NOTE_SECONDS 0x01
#define NOTE_USECONDS 0x02
#define NOTE_NSECONDS 0x04
#define NOTE_ABSOLUTE 0x08
#define NOTE_CRITICAL 0x10
#define NOTE_BACKGROUND 0x20
#define NOTE_LEEWAY 0x40

// need to catch the following usage if it happens ..
// we simply return '0' as a value probably not correct

#define NOTE_VM_PRESSURE ({LINUX_PORT_ERROR(); 0;})

/*
* Stub out misc linking and compilation attributes
Expand Down Expand Up @@ -135,8 +143,5 @@ struct kevent64_s {
#define __OSX_AVAILABLE_BUT_DEPRECATED_MSG(a,b,c,d,msg) //


// Print a warning when an unported code path executes.
#define LINUX_PORT_ERROR() do { printf("LINUX_PORT_ERROR_CALLED %s:%d: %s\n",__FILE__,__LINE__,__FUNCTION__); } while (0)


#endif /* __OS_LINUX_BASE__ */
98 changes: 96 additions & 2 deletions src/shims/linux_stubs.c
Original file line number Diff line number Diff line change
Expand Up @@ -84,11 +84,105 @@ int sysctlbyname(const char *name, void *oldp, size_t *oldlenp,
LINUX_PORT_ERROR();
}

int kevent64(int kq, const struct kevent *changelist, int nchanges, struct kevent *eventlist, int nevents,unsigned int flags, const struct timespec *timeout)
#if 0

// this code remains here purely for debugging purposes
// ultimately it can be deleted

DISPATCH_NOINLINE
static const char *
_evfiltstr(short filt)
{
switch (filt) {
#define _evfilt2(f) case (f): return #f
_evfilt2(EVFILT_READ);
_evfilt2(EVFILT_WRITE);
_evfilt2(EVFILT_AIO);
_evfilt2(EVFILT_VNODE);
_evfilt2(EVFILT_PROC);
_evfilt2(EVFILT_SIGNAL);
_evfilt2(EVFILT_TIMER);
#if HAVE_MACH
_evfilt2(EVFILT_MACHPORT);
_evfilt2(DISPATCH_EVFILT_MACH_NOTIFICATION);
#endif
_evfilt2(EVFILT_FS);
_evfilt2(EVFILT_USER);
#ifdef EVFILT_VM
_evfilt2(EVFILT_VM);
#endif
#ifdef EVFILT_SOCK
_evfilt2(EVFILT_SOCK);
#endif
#ifdef EVFILT_MEMORYSTATUS
_evfilt2(EVFILT_MEMORYSTATUS);
#endif

_evfilt2(DISPATCH_EVFILT_TIMER);
_evfilt2(DISPATCH_EVFILT_CUSTOM_ADD);
_evfilt2(DISPATCH_EVFILT_CUSTOM_OR);
default:
return "EVFILT_missing";
}
}

#if 0
#define dbg_kevent64(fmt...) do { printf(fmt); } while(0)
#define dbg_cond_kevent64(cond,fmt...) do { if (cond) printf(fmt); } while(0)
#else
#define dbg_kevent64(fmt...) do { } while(0)
#define dbg_cond_kevent64(cond,fmt...) do { } while(0)
#endif


int kevent64(int kq, const struct kevent64_s *changelist_c, int nchanges, struct kevent64_s *eventlist,
int nevents, unsigned int flags, const struct timespec *timeout)
{
return kevent(kq,changelist,nchanges,eventlist,nevents,timeout);
// Documentation is not really clear. Instrument the code to make sure
// we can do type conversions right now between kevent64 <-> kevent, where as
// kevent64 uses the ext[2] extension. So far we only see these used in the EVFILT_TIMER.
// right now we do this in the way into kevent, we also have to assert that
// no more than 1 change or one event is passed until we get a better handle of the
// usage pattern of this. (Hubertus Franke)

struct kevent64_s *changelist = (struct kevent64_s*) changelist_c; // so we can modify it

#if 1
// lets put some checks in here to make sure we do it all correct
// we can only convert kevent64_s -> kevent for a single entry since kevent64_s has ext[0:1] extension
if ((nchanges > 1) || (nevents > 1))
LINUX_PORT_ERROR();
if (nchanges) {
dbg_kevent64("kevent64(%s,%x,%x): cl.ext[0,1]=%lx:%ld %lx:%ld cl.data=%lx:%ld\n",
_evfiltstr(changelist->filter), changelist->flags, changelist->fflags,
changelist->ext[0], changelist->ext[0],
changelist->ext[1], changelist->ext[1],
changelist->data, changelist->data);
if ((changelist->filter == EVFILT_TIMER) && (changelist->fflags & NOTE_ABSOLUTE)) {
// NOTE_ABSOLUTE is not recognized by the current kevent we need to convert this
// into a relative. Consider fiddling with creating relative events instead (didn't work
// on first attempt). We also ignore the LEEWAY. Finally we must convert from
// NSECS to MSECS (might have to expand to deal with OTHER NOTE_xSECS flags

//changelist->data -= _dispatch_get_nanoseconds();
//changelist->data -= time(NULL) * NSEC_PER_SEC;
dbg_kevent64("kevent64(%s,%x) data=%lx:%ld\n",
_evfiltstr(changelist->filter),changelist->fflags,
changelist->data,changelist->data);
//changelist->data /= 1000000UL;
//if ((int64_t)(changelist->data) <= 0) changelist->data = 1; // for some reason time turns negative
}
}
#endif
// eventlist can not return more than 1 event type coersion doesn't work
int rc = kevent(kq,(struct kevent*) changelist,nchanges,(struct kevent*) eventlist,nevents,timeout);
if (rc > 1)
LINUX_PORT_ERROR();
return rc;
}

#endif

/*
* Stubbed out static data
*/
Expand Down
24 changes: 20 additions & 4 deletions src/source.c
Original file line number Diff line number Diff line change
Expand Up @@ -1858,13 +1858,27 @@ _dispatch_timers_get_delay(uint64_t nows[], struct dispatch_timer_s timer[],
return ridx;
}


#if HAVE_KEVENT64
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this block is wrong, and in any case should live in shims/time.h

I think what you mean here is "do we have support for NOTE_NSECONDS"
and not "do we have KEVENT64", you would break FreeBSD doing this.

Please do not mingle OS support with code, use shims/ and clean wrappers.

It'd be best to push NOTE_NSECOND support in libkqueue in the first place, which is probably easiest, so that you can use the thing directly anyway.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks. The intention initially was to get something running.
I agree that better place to get this moved is libkqueue which internally uses nsec time management anyway. We can squash this patch set, clean it up w/o kevent64(@libkqueue)
for now according to your suggestions (shims/time.h) and then do a full update on the
libkqueue to bring kevent64 semantics as known in BSD to that implementation.
Frankly I prefer that, though not sure yet how to do with the EVFILTER_TIMER.leeway semantics. Where will we host the libkqueue, seems like Haileys has not been active for a while.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The problem is that your patch most likely breaks Mac OS too, so we can't take that even for the sake of the linux port making progress.

the leeway argument is easy: it's always correct to ignore it. it's about "can I delay firing that timer a bit so that I can coalesce several timers firing approximatively at the same time and save power by waking up the CPU once" If you don't do it, the code is still correct.

# define kevent_set_ext1(ke,val) (ke)->ext[1] = (val)
# define adjust_delay(delay,at) (delay) += (at)
#else
# define kevent_set_ext1(ke,val) do { } while (0)
# define adjust_delay(delay,at) \
do { \
delay /= 1000000L; \
if ((int64_t)(delay) <= 0) delay = 1; /* for some reason time turns negative */ \
} while (0)

#endif

static bool
_dispatch_timers_program2(uint64_t nows[], _dispatch_kevent_qos_s *ke,
unsigned int qos)
{
unsigned int tidx;
bool poll;
uint64_t delay, leeway;
uint64_t delay, leeway, nowtime;

tidx = _dispatch_timers_get_delay(nows, _dispatch_timer, &delay, &leeway,
(int)qos);
Expand All @@ -1881,13 +1895,15 @@ _dispatch_timers_program2(uint64_t nows[], _dispatch_kevent_qos_s *ke,
_dispatch_trace_next_timer_set(
TAILQ_FIRST(&_dispatch_kevent_timer[tidx].dk_sources), qos);
_dispatch_trace_next_timer_program(delay, qos);
delay += _dispatch_source_timer_now(nows, DISPATCH_TIMER_KIND_WALL);
nowtime =_dispatch_source_timer_now(nows, DISPATCH_TIMER_KIND_WALL);
adjust_delay(delay,nowtime);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should be removed, and libkqueue updated to do conversions from ns to ms internally instead.


if (slowpath(_dispatch_timers_force_max_leeway)) {
ke->data = (int64_t)(delay + leeway);
ke->ext[1] = 0;
kevent_set_ext1(ke,0);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ditto

} else {
ke->data = (int64_t)delay;
ke->ext[1] = leeway;
kevent_set_ext1(ke,leeway);
}
ke->flags |= EV_ADD|EV_ENABLE;
ke->flags &= ~EV_DELETE;
Expand Down