www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Unused druntime code: Barrier, ReadWriteMutex, Condition

reply Denis Feklushkin <feklushkin.denis gmail.com> writes:
While working on FreeRTOS support several years ago I discovered 
that druntime's classes Barrier, ReadWriteMutex and Condition 
weren't used at druntime or by compiler (CI with mentioned 
classes disabled https://github.com/dlang/dmd/pull/23265)

In fact, Barrier and ReadWriteMutex aren't used at all in any std 
D libraries or by compiler and Condition is used only in Phobos.

They all rely on Condition. The problem with it is that Condition 
uses primitive provided by the OS (pthread_condattr if Posix). 
However, not all operating systems provide this primitive 
(FreeRTOS for example) and this causes a problem out of nowhere.

Since this code is not necessary for Dlang's core functionality, 
I propose moving all mentioned classes to Phobos with appropriate 
warning messages
Jun 14
next sibling parent reply "Richard (Rikki) Andrew Cattermole" <richard cattermole.co.nz> writes:
On 15/06/2026 9:36 AM, Denis Feklushkin wrote:
 While working on FreeRTOS support several years ago I discovered that 
 druntime's classes Barrier, ReadWriteMutex and Condition weren't used at 
 druntime or by compiler (CI with mentioned classes disabled https:// 
 github.com/dlang/dmd/pull/23265)
 
 In fact, Barrier and ReadWriteMutex aren't used at all in any std D 
 libraries or by compiler and Condition is used only in Phobos.
 
 They all rely on Condition. The problem with it is that Condition uses 
 primitive provided by the OS (pthread_condattr if Posix). However, not 
 all operating systems provide this primitive (FreeRTOS for example) and 
 this causes a problem out of nowhere.
 
 Since this code is not necessary for Dlang's core functionality, I 
 propose moving all mentioned classes to Phobos with appropriate warning 
 messages
Here is a "standard" addon that gets mentioned for FreeRTOS for read write mutex: https://github.com/michaelbecker/freertos-addons/blob/master/c/Source/read_write_lock.c Condition: https://github.com/michaelbecker/freertos-addons/blob/master/c%2B%2B/Source/ccondition_variable.cpp There are enough primitives in FreeRTOS to build these other sync primitives. If you don't want to implement these two types, feel free to version it off. Let's not go breaking existing code bases.
Jun 15
parent reply Denis Feklushkin <feklushkin.denis gmail.com> writes:
On Monday, 15 June 2026 at 09:07:54 UTC, Richard (Rikki) Andrew 
Cattermole wrote:

 There are enough primitives in FreeRTOS to build these other 
 sync primitives.
Strictly, my question wasn't related to FreeRTOS. I just want to understand why we keep such code that we don't use directly in the druntime. This code complicates porting without providing any benefit. Moving this code to Phobos allows us to put this issue aside along with other similar ones (like std.file on systems without filesystem) One day we'll have to quickly port the language to something trendy. And we won't be ready for it.
 There are enough primitives in FreeRTOS to build these other 
 sync primitives.
Most likely, these primitives do not exist in any OS - they are too high-level and can be implemented on the basis of "more primitive" primitives. (Posix implementation just provides convient wrapper, I think)
Jun 15
next sibling parent reply "Richard (Rikki) Andrew Cattermole" <richard cattermole.co.nz> writes:
On 15/06/2026 9:41 PM, Denis Feklushkin wrote:
 On Monday, 15 June 2026 at 09:07:54 UTC, Richard (Rikki) Andrew 
 Cattermole wrote:
 
 There are enough primitives in FreeRTOS to build these other sync 
 primitives.
Strictly, my question wasn't related to FreeRTOS. I just want to understand why we keep such code that we don't use directly in the druntime. This code complicates porting without providing any benefit. Moving this code to Phobos allows us to put this issue aside along with other similar ones (like std.file on systems without filesystem) One day we'll have to quickly port the language to something trendy. And we won't be ready for it.
 There are enough primitives in FreeRTOS to build these other sync 
 primitives.
Most likely, these primitives do not exist in any OS - they are too high-level and can be implemented on the basis of "more primitive" primitives. (Posix implementation just provides convient wrapper, I think)
They do. Windows Internals 7th edition, part 2. Page 205-206. Reasoning mentioned is that it has performance benefits. Its safe to assume some pthread implementations will have kernel backing as well.
Jun 15
parent Denis Feklushkin <feklushkin.denis gmail.com> writes:
On Monday, 15 June 2026 at 09:59:06 UTC, Richard (Rikki) Andrew 
Cattermole wrote:

 There are enough primitives in FreeRTOS to build these other 
 sync primitives.
Most likely, these primitives do not exist in any OS - they are too high-level and can be implemented on the basis of "more primitive" primitives. (Posix implementation just provides convient wrapper, I think)
They do. Windows Internals 7th edition, part 2. Page 205-206.
A cool take for an online debate in 2026 :-)
 Reasoning mentioned is that it has performance benefits.
Luckily, druntime don't use it for Windows
Jun 15
prev sibling parent reply Denis Feklushkin <feklushkin.denis gmail.com> writes:
On Monday, 15 June 2026 at 09:41:00 UTC, Denis Feklushkin wrote:

 Most likely, these primitives do not exist in any OS - they are 
 too high-level and can be implemented on the basis of "more 
 primitive" primitives. (Posix implementation just provides 
 convient wrapper, I think)
It is possible make PR on this base which will satisfy everyone. However, I'll wait for information about Windows (see previous message).
Jun 15
parent reply Denis Feklushkin <feklushkin.denis gmail.com> writes:
On Monday, 15 June 2026 at 10:35:39 UTC, Denis Feklushkin wrote:
 On Monday, 15 June 2026 at 09:41:00 UTC, Denis Feklushkin wrote:

 Most likely, these primitives do not exist in any OS - they 
 are too high-level and can be implemented on the basis of 
 "more primitive" primitives. (Posix implementation just 
 provides convient wrapper, I think)
It is possible make PR on this base which will satisfy everyone. However, I'll wait for information about Windows (see previous message).
The attempt to use standard Semaphore and Mutex in ondition implementation failed because the current Condition semantics requires nogc, but Mutex and Semaphore are classes and std.typecons.scoped isn't available in druntime. This is another argument for moving this code to Phobos
Jun 15
parent reply "Richard (Rikki) Andrew Cattermole" <richard cattermole.co.nz> writes:
On 16/06/2026 2:23 AM, Denis Feklushkin wrote:
 On Monday, 15 June 2026 at 10:35:39 UTC, Denis Feklushkin wrote:
 On Monday, 15 June 2026 at 09:41:00 UTC, Denis Feklushkin wrote:

 Most likely, these primitives do not exist in any OS - they are too 
 high-level and can be implemented on the basis of "more primitive" 
 primitives. (Posix implementation just provides convient wrapper, I 
 think)
It is possible make PR on this base which will satisfy everyone. However, I'll wait for information about Windows (see previous message).
The attempt to use standard Semaphore and Mutex in ondition implementation failed because the current Condition semantics requires nogc, but Mutex and Semaphore are classes and std.typecons.scoped isn't available in druntime.
The implementation can be extracted into a package struct. Nothing needs to break to fix this.
 This is another argument for moving this code to Phobos
There is no valid argument here. To move it requires breaking user code, and that is not an option.
Jun 15
next sibling parent reply Denis Feklushkin <feklushkin.denis gmail.com> writes:
On Monday, 15 June 2026 at 23:50:01 UTC, Richard (Rikki) Andrew 
Cattermole wrote:

 The attempt to use standard Semaphore and Mutex in ondition 
 implementation failed because the current Condition semantics 
 requires  nogc, but Mutex and Semaphore are classes and 
 std.typecons.scoped isn't available in druntime.
The implementation can be extracted into a package struct.
This leads to duplication of code what already available in `std.typecons.scoped`
 Nothing needs to break to fix this.
Why you use "break" to describe this? I do not propose break anything: I propose to add `public import` from `std.concurrency.rwmutex` (etc) into `core.sync.rwmutex` module with appropriate deprecation messages.
 This is another argument for moving this code to Phobos
There is no valid argument here. To move it requires breaking user code, and that is not an option.
Related - "Very telling quote": https://forum.dlang.org/post/lkfdcbhqjdphvoaekpxq forum.dlang.org (Very telling quote)
Jun 16
parent reply "Richard (Rikki) Andrew Cattermole" <richard cattermole.co.nz> writes:
On 16/06/2026 8:15 PM, Denis Feklushkin wrote:
 On Monday, 15 June 2026 at 23:50:01 UTC, Richard (Rikki) Andrew 
 Cattermole wrote:
 
 The attempt to use standard Semaphore and Mutex in ondition 
 implementation failed because the current Condition semantics 
 requires  nogc, but Mutex and Semaphore are classes and 
 std.typecons.scoped isn't available in druntime.
The implementation can be extracted into a package struct.
This leads to duplication of code what already available in `std.typecons.scoped`
No. I did not suggest anything to do with scoped. All of the state and function calls to make it platform independent does not need to live in a class. It can live in a struct instead and then be called into. ```d class Thing { private Thing2 thing2; void call() => thing2.call(); } package: struct Thing2 { void* state; void call() { } } ```
 Nothing needs to break to fix this.
Why you use "break" to describe this? I do not propose break anything: I propose to add `public import` from `std.concurrency.rwmutex` (etc) into `core.sync.rwmutex` module with appropriate deprecation messages.
Druntime cannot import phobos. Phobos depends upon druntime. Binary loading is acyclic, not cyclic. No PR that tries to do this will be merged.
Jun 16
next sibling parent reply Denis Feklushkin <feklushkin.denis gmail.com> writes:
On Tuesday, 16 June 2026 at 08:23:11 UTC, Richard (Rikki) Andrew 
Cattermole wrote:

 Druntime cannot import phobos.

 Phobos depends upon druntime.

 Binary loading is acyclic, not cyclic.
By the way, this is off-topic, I have one more suggestion on this matter sounding like: "druntime cannot import core.stdc" I.e., core.stdc shouldn't be necessary. Let the druntime use these functions through wrapper functions. There will be only about 10 of them in total, I think: malloc/free, some sync methods... This will solve 95% of porting issues to any system
Jun 16
parent reply "Richard (Rikki) Andrew Cattermole" <richard cattermole.co.nz> writes:
On 16/06/2026 10:32 PM, Denis Feklushkin wrote:
 On Tuesday, 16 June 2026 at 08:23:11 UTC, Richard (Rikki) Andrew 
 Cattermole wrote:
 
 Druntime cannot import phobos.

 Phobos depends upon druntime.

 Binary loading is acyclic, not cyclic.
By the way, this is off-topic, I have one more suggestion on this matter sounding like: "druntime cannot import core.stdc" I.e., core.stdc shouldn't be necessary. Let the druntime use these functions through wrapper functions. There will be only about 10 of them in total, I think: malloc/free, some sync methods... This will solve 95% of porting issues to any system
Chuck it into a module called core.internal.platform and sure. You shouldn't need wrapper functions for the most part. Aliases will suffice. I.e. malloc is perfectly fine as an API, just needs a different name so it can be swapped out easily.
Jun 16
parent reply Denis Feklushkin <feklushkin.denis gmail.com> writes:
On Tuesday, 16 June 2026 at 10:38:27 UTC, Richard (Rikki) Andrew 
Cattermole wrote:

 I.e., core.stdc shouldn't be necessary.
 
 Let the druntime use these functions through wrapper 
 functions. There will be only about 10 of them in total, I 
 think: malloc/free, some sync methods...
 
 This will solve 95% of porting issues to any system
Chuck it into a module called core.internal.platform and sure. You shouldn't need wrapper functions for the most part. Aliases will suffice. I.e. malloc is perfectly fine as an API, just needs a different name so it can be swapped out easily.
Yes, maybe aliases. Point is in restrictions for druntime developers to avoid them to use core.stdc functions directly exept available ~10 aliases, same on all platforms, same for Posix, non-Posix, with libc or without - this doesn't matter
Jun 16
parent "Richard (Rikki) Andrew Cattermole" <richard cattermole.co.nz> writes:
On 16/06/2026 10:48 PM, Denis Feklushkin wrote:
 On Tuesday, 16 June 2026 at 10:38:27 UTC, Richard (Rikki) Andrew 
 Cattermole wrote:
 
 I.e., core.stdc shouldn't be necessary.

 Let the druntime use these functions through wrapper functions. There 
 will be only about 10 of them in total, I think: malloc/free, some 
 sync methods...

 This will solve 95% of porting issues to any system
Chuck it into a module called core.internal.platform and sure. You shouldn't need wrapper functions for the most part. Aliases will suffice. I.e. malloc is perfectly fine as an API, just needs a different name so it can be swapped out easily.
Yes, maybe aliases. Point is in restrictions for druntime developers to avoid them to use core.stdc functions directly exept available ~10 aliases, same on all platforms, same for Posix, non-Posix, with libc or without - this doesn't matter
Yeah its a known issue with druntime when it comes to porting it. Its very all or nothing. So it was an easy yes, and I doubt anyone will have an opinion against it.
Jun 16
prev sibling parent Denis Feklushkin <feklushkin.denis gmail.com> writes:
On Tuesday, 16 June 2026 at 08:23:11 UTC, Richard (Rikki) Andrew 
Cattermole wrote:

 This leads to duplication of code what already available in 
 `std.typecons.scoped`
No. I did not suggest anything to do with scoped. All of the state and function calls to make it platform independent does not need to live in a class.
Condition class currently isn't cross-platform. Making it so is a another separate task. Moving it into Phobos for future generations to improvement would be the best solution, in my opinion. (Just at the moment when the rest druntime functionality for baremetal/multiplatform support is ready, Phobos 3 will appear, in which this can be taken into account.)
 Nothing needs to break to fix this.
Why you use "break" to describe this? I do not propose break anything: I propose to add `public import` from `std.concurrency.rwmutex` (etc) into `core.sync.rwmutex` module with appropriate deprecation messages.
Druntime cannot import phobos.
Oh, yes, you are right here. But we can copy and paste code to Phobos and deprecate same code in the drumtime for ~year. Obvious, anyone using Barrier class will be able to change the import line from core.sync.barrier to std.concurrency.barrier
Jun 16
prev sibling parent reply Dejan Lekic <dejan.lekic gmail.com> writes:
On Monday, 15 June 2026 at 23:50:01 UTC, Richard (Rikki) Andrew 
Cattermole wrote:

 To move it requires breaking user code, and that is not an 
 option.
Why not do what we typically did in the past - mark it deprecated with message that we are not deprecating it but actually moving somewhere else, and then after few months actually do it? Instead of repeating C++ mistakes, let's not fear breaking changes, and learn how to do them the right way... - If something is marked as deprecated with appropriate message for 6 months those who complain about broken code after that period, when the move actually happened should just, put it bluntly, shut the heck up.
Jun 16
parent reply "Richard (Rikki) Andrew Cattermole" <richard cattermole.co.nz> writes:
On 16/06/2026 9:54 PM, Dejan Lekic wrote:
 On Monday, 15 June 2026 at 23:50:01 UTC, Richard (Rikki) Andrew 
 Cattermole wrote:
 
 To move it requires breaking user code, and that is not an option.
Why not do what we typically did in the past - mark it deprecated with message that we are not deprecating it but actually moving somewhere else, and then after few months actually do it? Instead of repeating C++ mistakes, let's not fear breaking changes, and learn how to do them the right way... - If something is marked as deprecated with appropriate message for 6 months those who complain about broken code after that period, when the move actually happened should just, put it bluntly, shut the heck up.
1. It would need to be more like 6 years, not 6 months with such long release cycles. 2. There is nothing actually wrong with the code, it is working correctly. 3. All multi-threaded OS's should support these primitives. 4. There are alternatives to breaking code that are a better choice. There is a time and a place to break code, this isn't it.
Jun 16
next sibling parent reply Serg Gini <kornburn yandex.ru> writes:
On Tuesday, 16 June 2026 at 10:21:43 UTC, Richard (Rikki) Andrew 
Cattermole wrote:
 There is a time and a place to break code, this isn't it.
This is all good, but could you clearly specify the path for FreeRTOS support? How and when this could happen?
Jun 16
parent "Richard (Rikki) Andrew Cattermole" <richard cattermole.co.nz> writes:
On 16/06/2026 10:27 PM, Serg Gini wrote:
 On Tuesday, 16 June 2026 at 10:21:43 UTC, Richard (Rikki) Andrew 
 Cattermole wrote:
 There is a time and a place to break code, this isn't it.
This is all good, but could you clearly specify the path for FreeRTOS support? How and when this could happen?
I have given two good options to handle these two classes. Version them off like we do for bindings, or implement them on other primitives (which is common practice for that OS). Versioning is the quickest solution, and allows someone to come back later to implement the standard way. I have no preference of these two.
Jun 16
prev sibling parent reply Denis Feklushkin <feklushkin.denis gmail.com> writes:
On Tuesday, 16 June 2026 at 10:21:43 UTC, Richard (Rikki) Andrew 
Cattermole wrote:

 3. All multi-threaded OS's should support these primitives.
Why? Because someone 20 years ago, apparently by accident, implemented this code in the druntime? This code isn't necessary for the druntime, that's the point. And the operating system doesn't necessarily need to support it either. It's (I repeat myself, excuse me) too high-level sync primitive, and not all OSes can provide it.
Jun 16
parent reply "Richard (Rikki) Andrew Cattermole" <richard cattermole.co.nz> writes:
On 16/06/2026 10:37 PM, Denis Feklushkin wrote:
 On Tuesday, 16 June 2026 at 10:21:43 UTC, Richard (Rikki) Andrew 
 Cattermole wrote:
 
 3. All multi-threaded OS's should support these primitives.
Why? Because someone 20 years ago, apparently by accident, implemented this code in the druntime? This code isn't necessary for the druntime, that's the point. And the operating system doesn't necessarily need to support it either. It's (I repeat myself, excuse me) too high-level sync primitive, and not all OSes can provide it.
So version it off like we do with bindings. There is no reason to break existing code when we can do that. ```d version(FreeRTOS) version = NoBarrier; version(NoBarrier) { disable class Barrier {} } else { class Barrier { ... } } ```
Jun 16
next sibling parent reply Denis Feklushkin <feklushkin.denis gmail.com> writes:
On Tuesday, 16 June 2026 at 10:41:00 UTC, Richard (Rikki) Andrew 
Cattermole wrote:

 So version it off like we do with bindings.

 There is no reason to break existing code when we can do that.

 ```d
 version(FreeRTOS)
 	version = NoBarrier;
 ```
But this will break existing code which using Barrier when cross-compiling for FreeRTOS :-)
Jun 16
parent reply "Richard (Rikki) Andrew Cattermole" <richard cattermole.co.nz> writes:
On 16/06/2026 11:12 PM, Denis Feklushkin wrote:
 On Tuesday, 16 June 2026 at 10:41:00 UTC, Richard (Rikki) Andrew 
 Cattermole wrote:
 
 So version it off like we do with bindings.

 There is no reason to break existing code when we can do that.

 ```d
 version(FreeRTOS)
     version = NoBarrier;
 ```
But this will break existing code which using Barrier when cross- compiling for FreeRTOS :-)
Nobody is compiling for FreeRTOS using upstream druntime if it hasn't been ported. So there is nothing to break.
Jun 16
parent reply Denis Feklushkin <feklushkin.denis gmail.com> writes:
On Tuesday, 16 June 2026 at 11:14:25 UTC, Richard (Rikki) Andrew 
Cattermole wrote:

 Nobody is compiling for FreeRTOS using upstream druntime if it 
 hasn't been ported.

 So there is nothing to break.
I claim that this is accidentally added code that has been used in open source projects ~3 times or so (throughout the history of GitHub), and PRs what using of this code was rejected twice. Once code was sucessfully used 8 years ago in some 3rd party open project. Your opinion: we don't change our API because it will break user code. :-/ At the same time, there is no reason at the present time to make a cross-platform implementation of this algorithm - writing a such code "for the future" means planting a bomb under someone else's code because it will not be properly tested and used now. (Yes, my personal opinion is that it is not needed at all in std libraries) FreeRTOS: I'm only interested in it because it's unlike anything else we use in D. That is, if we implement support for it, we'll get a highly abstract druntime, which will make it much easier to add more traditional OSes/platforms. Ok, next: Windows will die in ~10 years (or maybe 15, yeah right! Many of us already using D more than 15 years, just to orient on the timeline. Who among us at that time would have believed that Linux would be built into Windows?) Posix is ​​a dead end, even for Linux (we could at least allocate memory not by maloc/free wrappers?) Obviously, new OSes will emerge on such timeline, at the very least because new types of hardware (persistent RAM?) will emerge. These OSes will use different APIs. How long has the battle for Wasm been going on? (Yes, I know there's a different problem there.) There's still no bare metal support, after ~15 years. Some kind of stagnation? On GitHub I found only one use of classes mentioned in this tpic, in code that's 8 years old. Let's break this classes, especially since it won't disappear, but will remain in Phobos!
Jun 16
parent Denis Feklushkin <feklushkin.denis gmail.com> writes:
On Tuesday, 16 June 2026 at 12:19:27 UTC, Denis Feklushkin wrote:
 On Tuesday, 16 June 2026 at 11:14:25 UTC, Richard (Rikki)
 Let's break this classes, especially since it won't disappear, 
 but will remain in Phobos!
(The train of thought suddenly stopped) Otherwise, without such decisions all ecosystem will remain to rot without any forward movement
Jun 16
prev sibling next sibling parent Denis Feklushkin <feklushkin.denis gmail.com> writes:
On Tuesday, 16 June 2026 at 10:41:00 UTC, Richard (Rikki) Andrew 
Cattermole wrote:

 So version it off like we do with bindings.

 There is no reason to break existing code when we can do that.

 ```d
 version(FreeRTOS)
 	version = NoBarrier;
 ```
But this will break existing code which using Barrier when cross-compiling for FreeRTOS :-)
Jun 16
prev sibling parent reply Nick Treleaven <nick geany.org> writes:
On Tuesday, 16 June 2026 at 10:41:00 UTC, Richard (Rikki) Andrew 
Cattermole wrote:
 ```d
 version(NoBarrier) {
 	 disable
 	class Barrier {}
 } else {
 ```
` disable` doesn't work with types. You can do ` disable new();` though. The spec should be clearer:
 A reference to a declaration marked with the  disable attribute 
 causes a compile time error.
https://dlang.org/spec/attribute.html#disable
Jun 17
next sibling parent "Richard (Rikki) Andrew Cattermole" <richard cattermole.co.nz> writes:
On 18/06/2026 7:19 AM, Nick Treleaven wrote:
 On Tuesday, 16 June 2026 at 10:41:00 UTC, Richard (Rikki) Andrew 
 Cattermole wrote:
 ```d
 version(NoBarrier) {
      disable
     class Barrier {}
 } else {
 ```
` disable` doesn't work with types. You can do ` disable new();` though. The spec should be clearer:
 A reference to a declaration marked with the  disable attribute causes 
 a compile time error.
https://dlang.org/spec/attribute.html#disable
That should really be fixed to make disable work on types.
Jun 17
prev sibling parent Nick Treleaven <nick geany.org> writes:
On Wednesday, 17 June 2026 at 19:19:41 UTC, Nick Treleaven wrote:
 On Tuesday, 16 June 2026 at 10:41:00 UTC, Richard (Rikki) 
 Andrew Cattermole wrote:
 ```d
 version(NoBarrier) {
 	 disable
 	class Barrier {}
 } else {
 ```
` disable` doesn't work with types. You can do ` disable new();` though. The spec should be clearer:
Filed issue & PR: https://github.com/dlang/dmd/issues/23289
Jun 20
prev sibling parent reply Walter Bright <newshound2 digitalmars.com> writes:
Thank you for your work supporting FreeRTOS!

I recommend checking github on the history of those functions. The PR's for
them 
may give a rationale for their existence.
Jun 15
parent Denis Feklushkin <feklushkin.denis gmail.com> writes:
On Monday, 15 June 2026 at 21:06:16 UTC, Walter Bright wrote:
 Thank you for your work supporting FreeRTOS!

 I recommend checking github on the history of those functions. 
 The PR's for them may give a rationale for their existence.
In dmd repository first commit containing mentioned above classes is literally the first commit that makes any sense: ``` commit 6837c0cd426f7e828aec1a2bdc941ac9b722dd14 (HEAD) Author: Sean Kelly <sean invisibleduck.org> Date: Fri Sep 19 02:35:12 2008 +0000 First commit of the D Runtime Project. This includes a fully functional runtime for DMD/D1. Support for DMD/D2 is next on the agenda. ``` And I see that this classes simply exist and are not used anywhere. I used commands like: ``` git log -G " Barrier" ``` to find anything. I also searched in Phobos repository and didn't find anything. Github reports one unsuccessful attempt to make PR with ReadWriteMutex, but it was declined. Maybe I'm looking in the wrong place, I'm not a big expert on git kung fu.
Jun 15