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

Thread safety changes #19

Closed
wants to merge 12 commits into from
Closed

Thread safety changes #19

wants to merge 12 commits into from

Conversation

mleise
Copy link

@mleise mleise commented Sep 20, 2014

This pull request addresses the mentioned basic thread safety issues while keeping the API mostly the same. In particular I changed the following:

  • All methods documented as overridable (writeLogMsg, beginLogMsg, logMsgPart and finishLogMsg) are now protected. They are the ones who no longer need to implement thread-safety themselves and never get called by user code. They are only called by library code that synchronizes with the Logger's mutex before calling them. When implementing your own loggers, remember to not accidentally make the overrides public.
  • stdlog can no longer be read out since we cannot guarantee the returned pointer will still be the stdlog when we call a method on it. (For user code that needs to work with stdlog directly we could add a sort of stdlogApply function that takes a delegate with the code to execute in the context of stdlog. stdlogApply would lock the global mutex before executing said delegate.)
  • stdlog when set to null will swap the default logger back in.
  • The unittesting symbols like randomString() no longer leak into user code.
  • The function isLoggingActive is now split into an compile time constant and a template (isLoggingActiveAt) for a specific level. The return values are the same, but code & symbols for the functions are no longer emitted.
  • Compiler now warns about unimplemented Logger methods (instead of ending with linker errors).
  • All methods except the ones documented as overridable have been made final. This is to implement the thread-safety measures inside these other methods and be safe from later overrides that break them.

A word on Logger chaining: A special method for logging chains has been added to replace the now inaccessible writeLogMsg() with the name forwardMsg(). As public a method it will do the proper synchronization before calling writeLogMsg() internally and not check the globalLogLevel again.

Note: This pull request does not address the recursive logger call issue.

…omplain about missing implementations, but instead assume they will be in some .o file that is later passed to the linker.
…oreach(). Possibly a compiler bug in 2.066 master.)
* User code can no longer directly read out the stdlog, because by the time it has the reference, it might already be obsolete.
  (Later an `opApply` style function could be provided to execute functions/delegates in the context of a locked stdlog.)
* The stdlog property was split up into a public setter `stdlog` and a package getter `stdlogImpl`, because the compiler doesn't like different visibility for getter and setter.
* All module level functions dealing with the stdlog now synchronize with the global `__stdloggermutex`.
…s generated and emitted for `isLoggingActive` and it can be called at runtime. This commit turns the template function into just a template `isLoggingActiveAt` and a global bool flag `isLoggingActive`, so they can both be evaluated without parenthesis now and don't end up as functions in the final executable.
…able to gain more control over the implementation details when I implement thread safety measures. Made `fatalHandler` accessible as a property to allow synchronization in later commits.

Also made `writeLogMsg` protected, so it can assume it is properly synchronized already by the public calls calling it. To log a pre-built message `forwardMsg` can now be used. (See `FileLogger`).
… would revert the setting.

And while I was at it, I changed `stdlog`s behavoir on assignment of `null`: It will now put the default logger back in place.
Logger now has a mutex to protect its public API.
The module level functions don't perform any runtime checks themselves to avoid races. Instead the logger does all checking under protection of its mutex.
`globalLogLevel` will be evaluated only once for any public logging call and thus needs no global locking.
All overrides of `writeLogMsg`, `beginLogMsg`, `logMsgPart` and `finishLogMsg` have `protected` visibility now, since they expect their logger to be already under mutex protection and must not be publically visible.
@burner
Copy link
Owner

burner commented Sep 20, 2014

overall the patches appear to be very good. I will a closer look tomorrow or monday.

You should create this PR for my phobos logger branch so your contribution shows up in git correctly. moving git history from one repo to the next is just a pain.

anyway thanks alot

{
return this.logLevel_;
synchronized (mutex) return this.logLevel_;

Choose a reason for hiding this comment

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

Couldn't this use an atomic read instead? Locking seems overkill

@JakobOvrum
Copy link

stdlog can no longer be read out since we cannot guarantee the returned pointer will still be the stdlog when we call a method on it.

How is that a problem?

@mleise
Copy link
Author

mleise commented Sep 20, 2014

@JakobOvrum You are right, a single read doesn't require locking. I will change that.
With read-access to stdlog you can do a lot of bad things. The code that deals with stdlog should just keep a pointer to the logger that got assigned to it.
If you want to write code that reflects on the current stdlog somehow, that stdlogApply option is still open that guarantees that the stdlog remains in place during the examination. It would be no more than synchronized(__stdloggermutex) dlg();. Just getting a pointer to a Logger that has once been or still is the stdlog doesn't seem to make sense to me. If there is any use case that is better solved with direct pointer access I will add it back in with a usage note.

@JakobOvrum
Copy link

Being the stdlog at the time of access seems plenty sufficient. What bad things can you do with that?

@mleise
Copy link
Author

mleise commented Sep 20, 2014

Somehow I don't see the point in arguing that. I want to see questions on d.learn, StackOverflow or bug reports about not being able to read stdlog to see what people tried to achieve and if the correct approach is direct access. For now it is not possible to get at this object that may not be "current" any more by the time you work with it. It seems to me that it adds to logical correctness of code using stdlog. (Again, stdlogApply() might be the function you are looking for instead of direct access.)

@JakobOvrum
Copy link

I don't see the point in stdlogApply. Nobody is expecting a property to magically stay "up to date" after being read. What if I wanted to pass stdlog to a function operating on a Logger or whatever? It doesn't matter at all if the stdlog global variable is changed between reading stdlog and using it - I got what I bargained for at the time of reading and it's not a problem if stdlog was changed.

@mleise
Copy link
Author

mleise commented Sep 20, 2014

Yes, we do expect properties to stay the same while we operate on them. That is because we work on them in a thread local contexts all the time. appWindow.label1.font.family = "Arial" would make little sense if we didn't have the guarantee that the is not modified concurrently.
See how TickDuration.currSystemTick is named current? In case of time we are fine a current snapshot of it, because it has value in its own. We can use it to describe when something happened or calculate a time difference. A logger doesn't have such properties. I claim that there is no use case for working with a previous snapshot of the globally shared stdlog.
Now that we exchanged our thoughts, would you want me to add read access to stdlog back tomorrow with your other change ? 👍 👎

@mleise
Copy link
Author

mleise commented Sep 21, 2014

Ok, I reopened this pull at burner/phobos#2 as requested by Robert.

@mleise mleise closed this Sep 21, 2014
@mleise mleise deleted the thread-safety branch September 21, 2014 06:29
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

3 participants