Skip to content
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

support for linux scheduler and timer #64

Open
wants to merge 38 commits into
base: master
Choose a base branch
from

Conversation

neo5167
Copy link

@neo5167 neo5167 commented Jan 27, 2018

Linux support for scheduler and timer with epoll, timerfd, eventfd, and other such sundry stuff. I am restructuring the code with less ifdefs. But I want to do that with guidance from you guys. Also, its a fork of an older version. I am working rebasing it to something more recent as well. In this PR, please comment on how to structure the code so that we can move platform dependent stuff into something more manageable.

Copy link
Owner

@lewissbaker lewissbaker left a comment

Choose a reason for hiding this comment

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

@neo5167 Thanks very much for the PR.

I've had a read over the code and made some notes on some issues I found.

I think some of the functions with #ifdefs are a bit messy where we're trying to keep some common logic but then also having Linux-specific and Windows-specific parts. I wonder whether it would be more maintainable to put the #ifdefs outside of the function for some of these functions and cop a little bit of duplication between Windows/Linux versions in return for more readable code.

I'm also considering separating out the platform-specific bits into separate *_win32.cpp or *_linux.cpp files for some abstractions rather than sprinkling #ifdef around everywhere. It may require some refactoring to get there, though, so we can move towards that direction in time.

lib/linux.cpp Outdated
{
m_mqdt = -1;
uuid_t unique_name;
const char* cppcoro_qname_prefix = "/cppcoro-";
Copy link
Owner

Choose a reason for hiding this comment

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

It's a pity the Linux API doesn't provide a way to create anonymous message queues...

lib/linux.cpp Outdated
for(;;)
{
uuid_generate(unique_name);
uuid_unparse(unique_name, m_qname + sizeof(cppcoro_qname_prefix));
Copy link
Owner

Choose a reason for hiding this comment

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

This sizeof(cppcoro_qname_prefix) is really just doing a sizeof(const char*) which will always be 4 or 8.
I assume you meant for this to be using strlen(cppcoro_qname_prefix)?
Or perhaps declare cppcoro_qname_prefix to have type const char[10]?

lib/linux.cpp Outdated
{
close(m_epollfd);
assert(mq_close(m_mqdt) == 0);
assert(mq_unlink(m_qname) == 0);
Copy link
Owner

Choose a reason for hiding this comment

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

Won't these calls to mq_close and mq_unlink be compiled out under optimised builds when NDEBUG is defined?

Can the calls be moved out of the assert() statements and just assert() the comparison of the result.

lib/linux.cpp Outdated
}

message qmsg;
ssize_t status = mq_receive(m_mqdt, (char*)&qmsg, sizeof(message), NULL);
Copy link
Owner

Choose a reason for hiding this comment

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

I think there might be a possible race condition here if multiple threads concurrently call dequeue_message() that could cause one of the threads to block on the mq_receive call.
eg. consider if there is a single item in the queue and this signals the epoll handle. Both threads enter dequeue_message() and the call to epoll_wait() returns immediately with 1 for both threads since the message queue file descriptor is ready. The first thread to call mq_receive() dequeues the only message and the second thread to call mq_receive() blocks, waiting for another item to be queued to the message queue.

This may not be an issue in practice for calls that pass true to the wait parameter, but could lead to long delays for calls that pass false to concurrent calls.


#if CPPCORO_OS_LINUX
#define THREAD_ID unsigned long long
#define GET_THIS_THREAD_ID get_thread_id()
Copy link
Owner

Choose a reason for hiding this comment

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

Why are all of these macros necessary?

As far as I can see, all of the usages down below were previously just comparing std::thread::id values, so I don't quite follow why we need to try and convert the thread id into an unsigned long long.
I would have thought that std::this_thread::get_id() would work just fine.

Is it an issue with unresolved symbols for the operator<< for std::thread::id due to the use of the doctest CHECK() macros?

Copy link
Owner

Choose a reason for hiding this comment

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

I'd really rather avoid use of macros like this here if possible.

If it's really still needed then perhaps just use a typdef and write a local get_thread_id() function for all platforms?

Copy link
Author

Choose a reason for hiding this comment

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

Sadly, on Linux thread id's are are not comparable directly. Have to convert to unsigned long long first to be able to compare. I will remove the macros and add functions instead.

#include <sys/epoll.h>
#include <unistd.h>

typedef int DWORD;
Copy link
Owner

Choose a reason for hiding this comment

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

I'd like to avoid adding new global-scope typedefs and #defines like this in public headers.
I don't want to introduce any issues or potential conflicts with other libraries that may be used in conjunction with cppcoro.

Copy link
Owner

Choose a reason for hiding this comment

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

It looks like this is only required for timeout values inside cppcoro::io_service::timer_thread_state::run(), so maybe its definition could be localised to that file?

Copy link
Author

Choose a reason for hiding this comment

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

Makes sense. Fixed it.

@@ -0,0 +1,63 @@
#pragma once
Copy link
Owner

Choose a reason for hiding this comment

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

Can you change this to use #ifdef include guards to be consistent with other headers?

Copy link
Owner

Choose a reason for hiding this comment

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

Can you also add a copyright/license header as per the existing source files?

Please attribute copyright to the appropriate entity.

Copy link
Author

Choose a reason for hiding this comment

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

Will have to circle back on this. Have to speak with our team here to get the appropriate rights entity name.

Copy link
Author

Choose a reason for hiding this comment

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

Done.

@@ -76,8 +84,8 @@ namespace cppcoro
template<typename REP, typename PERIOD>
[[nodiscard]]
timed_schedule_operation schedule_after(
const std::chrono::duration<REP, PERIOD>& delay,
Copy link
Owner

Choose a reason for hiding this comment

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

There are a number of unnecessary whitespace changes in these commits.

Have you tried running clang-format over the files?

Copy link
Author

Choose a reason for hiding this comment

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

Will circle back on this. I am fixing my editor to have the same whitespace language as yours.

Copy link
Author

Choose a reason for hiding this comment

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

Alright. Things are now "tab"-bed according to clang-format-6.0.el from my emacs. That fixed it.

lib/linux.cpp Outdated
uuid_t unique_name;
const char* cppcoro_qname_prefix = "/cppcoro-";

if(NAME_MAX < UUID_STRING_SIZE + sizeof(cppcoro_qname_prefix) + 1)
Copy link
Owner

Choose a reason for hiding this comment

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

The sizeof(cppcoro_qname_prefix) here will be sizeof(const char*) and not sizeof("/cppcoro-").
I assume that was not the intent here?

Copy link
Author

Choose a reason for hiding this comment

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

Yikes. Meant strlen. Good catch!

lib/linux.cpp Outdated
attr.mq_msgsize = sizeof(cppcoro::detail::linux::message);
attr.mq_curmsgs = 0;

m_mqdt = mq_open((const char*)m_qname, O_RDWR | O_CREAT | O_EXCL | O_CLOEXEC, S_IRWXU, &attr);
Copy link
Owner

Choose a reason for hiding this comment

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

I don't think the (const char*)m_qname cast is necessary here.
There should be an implicit decay cast from char[NAME_MAX] to const char* possible here.

Copy link
Author

Choose a reason for hiding this comment

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

Yup!

The clang mainline has now been branched for clang-6 and mainline now uses clang-7 version.
@neo5167
Copy link
Author

neo5167 commented Feb 20, 2018

@lewissbaker Cool. Thanks for the comments. Working on the easiest ones now. For the more complex ones, let's chat in the comments on how to proceed.

@lewissbaker
Copy link
Owner

@neo5167 How are you going with the changes? Any questions I can help you with?

@neo5167
Copy link
Author

neo5167 commented Mar 6, 2018

@lewissbaker Sorry. Progress has been a little slow. I am hoping to send another commit in the next several days. Plan is to fix the comments by end of this month.

Uran198 and others added 12 commits March 9, 2018 17:32
If the library is used as part of a bigger project some definitions can
be provided via external build files.
Remove possible warnings with redefinitions of WIN32_LEAN_AND_MEAN.
Several tests are currently failing due to what seems to be compiler bugs.

Ignore tests for now and revisit once MSVC 15.7 is released.
Update appveyor.yml to ignore x86 optimised failures
Correct file_write_operation's friend class
The AppVeyor 'Visual Studio 2017 Preview' image has now been updated with
VS 2017.7 Preview 2
The msvcurt[d].lib is actually intended for C++/CLI usage and
seems to no longer being bundled with the default VS install
in more recent Visual Studio 2017 installs.

Should fix lewissbaker#73
@neo5167
Copy link
Author

neo5167 commented Apr 11, 2018

@lewissbaker take a look at the latest commit. Also, any ideas on how we should proceed with the whole ifdef thing? Is the main branch still ifdef based or have you already structured it more cleanly?

@neo5167
Copy link
Author

neo5167 commented Apr 16, 2018

@lewissbaker I was thinking of working on file support at a later time but push this PR through first. What do you think? If that is ok then I will work on rebasing with the main... let me know...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants