Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Feature/cleanup rawdata #41

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 10 commits into from
May 30, 2020
Merged

Conversation

Jeroen88
Copy link

Reopening #26 on new master.

Jeroen88 added 3 commits April 30, 2020 09:55
…second copy of the same data. Small API change, if no data is available, an empty string is returned instead of a NULL. Also readValue() returns a reference to m_value now, thus saving a copy constructor and a second copy of the same string in the sketch
@h2zero
Copy link
Owner

h2zero commented May 10, 2020

Well I was going to get rid of the string use all together but this works as well.

@Jeroen88
Copy link
Author

I was a little surprised about the std::string use at some places, but the author uses it as a general container for data at some places. The advantage is that you do not have to think about allocation, destruction, reallocation, etc. Haven't seen it before and had to get used to it, but why not?

@h2zero
Copy link
Owner

h2zero commented May 10, 2020

It's a nice quick way of doing allocation, but it depends on the implementation of stdlib as to how much data it actually uses. I think this one will reallocate 1.5x the amount needed but it could be 2x or more.

@Jeroen88
Copy link
Author

I think this one will reallocate 1.5x the amount needed but it could be 2x or more.

I didn't know that...

@h2zero
Copy link
Owner

h2zero commented May 10, 2020

It's not a big deal as most of the time the data will be less than the 20 bytes so it probably won't reallocate up to that point. It's just when you add say another 20 bytes it will allocate 30 or more so it has space to use if you add more data, prevents too many allocations happening.

@h2zero
Copy link
Owner

h2zero commented May 19, 2020

Merging this soon, waiting for testing with semaphore changes (might need to alter code here).

@Jeroen88
Copy link
Author

Okay, let me know if you need some changes (although this change is very straight forward)

@h2zero
Copy link
Owner

h2zero commented May 20, 2020

Been thinking about this and #49, if combined creates the possibility of a segfault.

Scenario:
Two tasks running 1 updates a display with periodic information with the notified value, the other acts on immediate information and perhaps controls a relay or some other device. Now if the notifications happen every 60 seconds but the second thread needs to know the immediate value and calls a read() operation, say at the 59.99 second mark, using rawData() it will get a pointer to data that is about to be invalidated in 0.01 seconds and segfault while accessing it.

That scenario might seem unlikely and preventable with the timestamp idea (thank you, it's great) but would require the user to properly implement the handling of it (check before reading, etc.). Also, since there is no way to know how the user application will use the pointer to std::string.data() we cannot implement a semaphore type protection mechanism.

From here there are 2 solutions I can see. 1 we can use a semaphore to protect the data and instead of a pointer we return a copy of the value (std::vector<uint8_t> preferably). 2 we do as already exists in master and malloc/copy the data and return a pointer to it, but implement a semaphore protection mechanism as well.

Option 1 is my preference but breaks compatibility, however it also takes care of the malloc/free issue and lets the application do the work. Option 2 already exists but needs protection added.

I'm open to any other solutions, this is just my current thoughts. As far as this library is concerned stability is my top priority, better to use some extra resources than crash an application IMHO.

@Jeroen88
Copy link
Author

stability is my top priority, better to use some extra resources than crash an application IMHO

I fully agree with you!

I have a third option. Completely remove readRawData(). It is a bad idea to return pointers to volatile internal data. Yes this breaks the API, but the alternative is easy: the user can safely use std::string value = ... readValue(); const char *rawData = value.data(). This gives the same semantics freeing the library of keeping an unnecessary copy of the data.

@h2zero
Copy link
Owner

h2zero commented May 22, 2020

Yes I believe this would be the correct option. I prefer not to break the api but in this case it seems necessary.

I think in the future the read results should be changed to something else. Perhaps we could use the NimBLEValue class to provide safe data access. Then the value could be stored however and provide methods for type conversion.

@Jeroen88
Copy link
Author

Removed getRawData() and changed readValue() back to return a std::string value again instead of a reference, just to be sure.

I think getDataLength() could be removed as well, since the user can change this to sdt::string value = pCharacteristic->readValue(); size_t dataLength = value.size(); which seems more logical to me.

@Jeroen88
Copy link
Author

Perhaps we could use the NimBLEValue class to provide safe data access.

Yes that seems a valid option, pro: this is consistent with the server side of the library (although I do not like the incrementing of the value there, I think the main program should prepare the value and pass it in one time to the library), con: an extra layer of abstraction that is not really necessary.

@h2zero
Copy link
Owner

h2zero commented May 23, 2020

I think getDataLength() could be removed as well,

@Jeroen88 agreed!

Thanks for removing the reference as well, that would have been problematic, the copy is a necessity in this case.

@Jeroen88
Copy link
Author

@h2zero Updated to latest master and removed getDataLength()

@h2zero
Copy link
Owner

h2zero commented May 23, 2020

Great, thanks!

@h2zero h2zero force-pushed the feature/cleanup-rawdata branch from b3a0ebe to a4cf80a Compare May 30, 2020 02:14
@h2zero h2zero merged commit 9877d96 into h2zero:master May 30, 2020
h2zero added a commit that referenced this pull request May 30, 2020
Previously getRawData() made an unnecessary copy of the remote characteristic value data in order to return a uint8_t*. The resources used for this was unjustified by the value it provided as templates to retrieve such data have been added. Also the application writer could cast the std::string result of readValue() and/or getValue() however they choose using the data() method on the container if desired.

getDataLength() is also an unnecessary function as the length can be retrieved by the returned std::string from readValue() and/or getValue() with the length() method.

Co-authored-by: h2zero <[email protected]>
@Jeroen88 Jeroen88 deleted the feature/cleanup-rawdata branch May 31, 2020 07:15
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.

2 participants