Replacement of deprecated API OSAtomicIncrement32Barrier for atomically increment/decrement variable - multithreading

I recently upgraded to XCode 9.2(macos 10.13) where I noticed that apple has deprecated some API from OSAtomic like OSAtomicIncrement32Barrier or OSAtomicDecrement32Barrier. We are using these APIs to increment or decrement our variable atomically.
According to apple, for atomic increment, atomic_fetch_add must be used instead of OSAtomicIncrement32Barrier. But argument type of OSAtomicIncrement32Barrier and its replacement atomic_fetch_add is very different. Former API required volatile int32_t * as an input argument but latter requires volatile atomic<_Tp>*. We have a int32_t variable whose value needs to be increment or decrement atomically.
Due to legacy code, I cannot change the variable type from int32_t to std::atomic<int32_t> which is required to call atomic_fetch_add.
I worked out some solution but I am not sure whether it will properly increment or decrement the variable atomically in multi threaded enviroment.
For atomically increment int32_t variable using OSAtomicIncrement32Barrier current defined macro
#define AtomicIncrement(x) OSAtomicIncrement32Barrier ( &(x) )
Proposed replaced macro with use of new API(atomic_fetch_add)
#define AtomicIncrement(x) std::atomic<int32_t> var(x); \
std::atomic_fetch_add(&var, 1); \
x = std::atomic_load(&var);
Will this work as a replacement of above macro? If not, how can I replace existing deprecated API behaviour with the new API?
Also I cannot be able to change the variable type from int32_t to std::atomic<int32_t> as I already mentioned

Related

Does bc not limit a variable's scope?

Define the function in basic calculator bc as
define void f () { test=42; print "all done\n"; }
I'd have thought the value of test would be limited to the scope of the function f, but no, test equals 42 globally. Is there no way to limit the scope of variables in bc functions? I.e. is there are way to define local variables in bc?
You need to specify an AUTO_LIST in your function definition. From the bc manual,
`define' NAME `(' PARAMETERS `)' `{' NEWLINE
AUTO_LIST STATEMENT_LIST `}'
[...]
The AUTO_LIST is an optional list of variables that are for "local"
use. The syntax of the auto list (if present) is "`auto' NAME, ... ;".
(The semicolon is optional.) Each NAME is the name of an auto
variable. Arrays may be specified by using the same notation as used
in parameters. These variables have their values pushed onto a stack
at the start of the function. The variables are then initialized to
zero and used throughout the execution of the function. At function
exit, these variables are popped so that the original value (at the
time of the function call) of these variables are restored. The
parameters are really auto variables that are initialized to a value
provided in the function call. Auto variables are different than
traditional local variables because if function A calls function B, B
may access function A's auto variables by just using the same name,
unless function B has called them auto variables. Due to the fact that
auto variables and parameters are pushed onto a stack, `bc' supports
recursive functions.
So to keep the test variable "local" in your function, you'd use
define void f () { auto test; test=42; print "all done\n"; }

register_netdevice_notifier callback does not provide valid net_device

I work on Ubuntu kernel-mode netfilter module and need information about all network interfaces and their properties in module code.
Inside of init_module() I use register_netdevice_notifier() for that purpose. When callback function is called I can see correct event codes like up/down and other, but it seems that third parameter void* casted to net_device* provides object with invalid properties. ->name is empty string, ->if index is some nonsense number etc.
I tried debug version of module on kernel 3.19 and rebuild also on 4.2. Result is the same, I cannot read properties of net_device relating to event.
What can be problem ?
From what I can see from LXR, you need to call netdev_notifier_info_to_dev on the last parameter to get your net_device * (see here)

How to trigger COW for string when it doesn't fire automatically

I've got a record, see this question for background info.
TDigits = AnsiString; //Should be `= array of NativeUInt`, but string has COW
TBigint = record
Digit: TDigits; // Unsigned number, LSB stored in D[0], MSB in D[size-1]
Size: Byte; // Mininum = 4, maximum 127.
MSI: Byte; // Most significant (native)integer minimum=1, maximum=127
Sign: Shortint;
class operator Implicit(a: Integer): TBigint;
Background
I'm using a bignum class that (almost) works like normal integers.
So a:= 1000000*10000000*12000000*10000000*1000000; yields perfectly useful results.
For this purpose I use a record with class operators.
These trigger automatic type conversion and initialisation.
Except when there is no conversion, because I'm assigning a TBigint to another TBigint.
The solution
Use an Ansistring to store the core data, it's got copy-on-write and will clone itself when needed.
The problem: (COW does not work if Delphi does not know you're altering the string)
I've got a few pure assembler routines that manipulate the Digit dynamic array disguised as Ansistring.
However when I do something like this:
Label1.Caption:= BigintToStr(b);
..... this fires:
function BigintToStr(const X: TBigint): AnsiString;
var
..
LocX:= x; <<-- assignment, locX and X are joined at the hip.
repeat
D := DivBigint(LocX, 1000000000, LocX); <<-- this routine changes LocX
^^+-- but assembler routines bypass COW
X and LocX are joint at the hip, whatever happens to one happens to the other.
Clearly Delphi does not know that the asm routine DivBigint is changing LocX and therefore a COW is in order.
The workaround
If I change the routine to:
function BigintToStr(const X: TBigint): AnsiString;
var
..
LocX:= x;
LocX.Digit[2]:= #0; <<-- inconsequential change to force COW.
repeat
D := DivBigint(LocX, 1000000000, LocX);
Delphi gets all clued up and performs just fine.
LocX and X are unlinked and everything works fine.
However I don't want to be making silly changes in the middle of some empty space.
Is there a decent/proper/offical* way to force trigger COW in strings?
Something like a system call perhaps?
*circle your favourite option (with a handdrawn circle)
Should be a comment, but need more space...
If you need to call UniqueString or equivalent.
You might as well retain the dynamic record.
A quote from the manual:
Following a call to SetLength, S is guaranteed to reference a unique string or array -- that is, a string or array with a reference count of one. If there is not enough memory available to reallocate the variable, SetLength raises an EOutOfMemory exception.
Note that this behavior even applies when calling SetLength(Length(myArray));.
Delphi will make a copy for you and untangle the problem.
So it turns out there is no need for the complication with the AnsiStrings After all, as long as you call SetLength in every method that accepts the record as a var parameter.
Advantages
This has the added benefit that if you call SetLength to expand the array (as happens often) the added space will be zero-initialized. Something does does not happen with the AnsiString.
Furthermore there is no need to bother with size translations because your array of TXYZ already knows the size of its elements. When using AnsiString you need to add * SizeOf(somestruct) all over the place.
No typecasting is needed, simplifying the code; and in the debugger the data shows up as it is designed.
As you can see the two instances are no longer linked.
Every method that mutates the buffer should, before performing the modification, call UniqueString.
Ensures that a given string has a reference count of one.
In fact, this detail was supplied by Craig Young's comment to my answer to your earlier question.
If you are going to make this viable you are going to need to hide the buffer. Make it strict private. That means that you can only access it from methods of your record. And that way you can be sure that anything that modifies the buffer will call UniqueString.
Personally, I think that a better solution would be to make the type immutable.

Thread-Safeness of FloatToStr / DateToStr

I just found in the documentation that FloatToStr and DateToStr are not thread-safe in their one-paramater overloads. The reason is that they access localization information stored in global variables.
My question is: is this of any practical relevance if I do not change the format settings at runtime? As far as I understand it, I'm on the safe side as long as everyone only reads the format settings - even from multiple threads.
Is that true or am I missing something here?
Thanks.
FloatToStr, DateToStr and others similar functions are reading global format settings. So, if your application does not change these settings for these function calls, then it is thread safe. The following code on opposite is not thread safe:
DecimalSeparator := ',';
try
s := FloatToStr(123.45);
finally
DecimalSeparator := '.';
end;
When you need the tread safety and "local" format settings, then you have to use overloaded functions, which take as last parameter: AFormatSettings: TFormatSettings. So, to make above code thread safe you have to write:
var
fs: TFormatSettings;
GetLocaleFormatSettings(GetThreadLocale, fs);
fs.DecimalSeparator := ',';
s := FloatToStr(123.45, fs);
Notes:
GetLocaleFormatSettings and fs initialization may be called once and then fs may be used multiple times. This will speedup the code.
Instead of GetLocaleFormatSettings may be used TFormatSettings.Create. I am not sure when that was introduced, but I see that in Delphi XE.
Even the global settings can change when Application.UpdateFormatSettings (Delphi 7, don't know about Delphi XE) is True. When a user changes the Regional and Language options of Windows, this will be reflected in your application. You can circumvent this by setting UpdateFormatSettings to False, but even then you can't be sure, maybe there is some third party library you use that changes it.
I had some problems with our own application: Nowhere in our application the global formatsettings were changed, but still there was information loss because a float was converted to a string and when the string was converted back to float, the formatsettings were magically changed. (So you had this: 1.2 -> convert to string -> '1.2' -> black magic that changed formatsettings.decimalseparator -> convert to float -> 12).
My suggestion: only use the not thread-safe version for UI purposes so the user sees dates and floats the way he likes them to see, for everything else, use the thread-safe version. Conversions inside your application will then be consistent and don't give surprises.
If the global settings are not changed by another thread while FloatToStr or DateToStr are executed you are fine.
EDIT: one thing to keep in mind:
var
// Note: Using the global FormatSettings variable corresponds to using the
// individual global formatting variables and is not thread-safe.
FormatSettings: TFormatSettings absolute CurrencyString;
The global variable above is just an alias for the global variables listed below. It is possible to change them either through the FormatSettings variable or directly.
var
// Important: Do not change the order of these declarations, they must
// match the declaration order of the fields in TFormatSettings exactly!
CurrencyString: string deprecated 'Use FormatSettings.CurrencyString';
CurrencyFormat: Byte deprecated 'Use FormatSettings.CurrencyFormat';
CurrencyDecimals: Byte deprecated 'Use FormatSettings.CurrencyDecimals';
DateSeparator: Char deprecated 'Use FormatSettings.DateSeparator';
TimeSeparator: Char deprecated 'Use FormatSettings.TimeSeparator';
ListSeparator: Char deprecated 'Use FormatSettings.ListSeparator';
ShortDateFormat: string deprecated 'Use FormatSettings.ShortDateFormat';
LongDateFormat: string deprecated 'Use FormatSettings.LongDateFormat';
TimeAMString: string deprecated 'Use FormatSettings.TimeAMString';
TimePMString: string deprecated 'Use FormatSettings.TimePMString';
ShortTimeFormat: string deprecated 'Use FormatSettings.ShortTimeFormat';
LongTimeFormat: string deprecated 'Use FormatSettings.LongTimeFormat';
ShortMonthNames: array[1..12] of string deprecated 'Use FormatSettings.ShortMonthNames';
LongMonthNames: array[1..12] of string deprecated 'Use FormatSettings.LongMonthNames';
ShortDayNames: array[1..7] of string deprecated 'Use FormatSettings.ShortDayNames';
LongDayNames: array[1..7] of string deprecated 'Use FormatSettings.LongDayNames';
ThousandSeparator: Char deprecated 'Use FormatSettings.ThousandSeparator';
DecimalSeparator: Char deprecated 'Use FormatSettings.DecimalSeparator';
TwoDigitYearCenturyWindow: Word deprecated 'Use FormatSettings.TwoDigitYearCenturyWindow';
NegCurrFormat: Byte deprecated 'Use FormatSettings.NegCurrFormat';
I just had problem with decimal separator. Delphi's streaming system (readcomponent/writecomponent etc) simply changes it to '.' and after all the work is done, it is changed back to whatever it was.
So, when I used this system for my own purposes (serializing/deserializing rather complex structure) and decided to do it in separate thread, or even in several separate threads, it shot me to the leg: '.' were mixed with ',' somewhere.
Unfortunately, I saw in some other libraries when DecimalSeparator is simply changed in procedure with intention to change it back at the end (most careful ones put it in 'finally' clause), so if some of your code is executed when one of these libs are running in separate thread, using thread-safe versions of StrToFloat etc. is imperative.

Why does ATL COM map scanning code expect the first entry to be of _ATL_SIMPLEMAPENTRY type?

ATL provides a bunch of macros for creating so-called COM maps - chains of rules of how the QueryInterface() call behaves on a given object. The map begins with BEGIN_COM_MAP and ends with END_COM_MAP. In between the the following can be used (among others):
COM_INTERFACE_ENTRY, COM_INTERFACE_ENTRY2 - to ask C++ to simply cast this class to the corresponding COM interface
COM_INTERFACE_ENTRY_FUNC - to ask C++ to call a function that will retrieve the interface
Now the problem is I want to use COM_INTERFACE_ENTRY_FUNC for every interface I expose so that I can log all the calls - I believe it will help me debugging my component when it is deployed in the field. The implementation of CComObjectRootBase::InternalQueryInterface contains an ATLASSERT:
ATLASSERT(pEntries->pFunc == _ATL_SIMPLEMAPENTRY);
which implies that the following is allright:
BEGIN_COM_MAP
COM_INTERFACE_ENTRY( IMyInterface1 )
COM_INTERFACE_ENTRY_FUNC( __uuidof(IMyInterface2), 0, OnQueryMyInterface2 )
END_COM_MAP
since here the first entry results in _ATL_SIMPLEMAPENTRY type entry but the following is not:
BEGIN_COM_MAP
COM_INTERFACE_ENTRY_FUNC( __uuidof(IMyInterface1), 0, OnQueryMyInterface1 )
COM_INTERFACE_ENTRY_FUNC( __uuidof(IMyInterface2), 0, OnQueryMyInterface2 )
END_COM_MAP
since here the entry type will not be _ATL_SIMPLEMAPENTRY.
This makes no sense at all. Why am I enforced into having a "please, C++, do the static_cast" entry as the first entry of the COM map?
Upd: Resolved after many more hour of debugging, answer added.
Inside ATL there's AtlInternalQueryInterface() that actually does scan the COM map. Inside it there's this code:
if (InlineIsEqualUnknown(iid)) // use first interface
{
IUnknown* pUnk = (IUnknown*)((INT_PTR)pThis+pEntries->dw);
// call AddRef on pUnk, copy it to ppvObject, return S_OK
}
this code actually relies on the first entry of the table being of _ATL_SIMPLEMAPENTRY type since it expects that _ATL_INTMAP_ENTRY::dw stores an offset from the current object this pointer to the necessary interface. In the use cited in the question if the first entry is this one:
COM_INTERFACE_ENTRY_FUNC( __uuidof(IMyInterface1), 0, OnQueryMyInterface1 )
the entry will be of wrong type, but the _ATL_INTMAP_ENTRY::dw will be zero (second parameter to the macro) and the code will happily work each time returning this pointer as IUnknown*. But if the second macro parameter which corresponds to a pass this value into the function specified as the third parameter variable is not zero the program will use that value as the offset and could run into undefined behaviour.

Resources