Skip to content
This repository was archived by the owner on Oct 12, 2022. It is now read-only.
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit f111c3d

Browse files
radcapricornwilzbach
authored andcommittedMar 29, 2018
assumeUnshared: convert shared lvalue to a non-shared one
1 parent f6f537f commit f111c3d

File tree

2 files changed

+172
-0
lines changed

2 files changed

+172
-0
lines changed
 
+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
`core.atomic.assumeUnshared` has been added
2+
3+
$(REF assumeUnshared, core,atomic) allows to convert a shared lvalue to a non-shared lvalue
4+
5+
---
6+
shared static int i;
7+
8+
// i is never used outside of synchronized {} blocks...
9+
10+
synchronized
11+
{
12+
++i; // ERROR: cannot directly modify shared lvalue
13+
14+
atomicOp!"+="(i, 1); // possible overhead
15+
16+
// Directly modify i
17+
assumeUnshared(i) += 1;
18+
// or:
19+
++assumeUnshared(i);
20+
// or:
21+
i.assumeUnshared += 1;
22+
}
23+
---

‎src/core/atomic.d

+149
Original file line numberDiff line numberDiff line change
@@ -267,6 +267,58 @@ version( CoreDdoc )
267267
* loads and stores after the call.
268268
*/
269269
void atomicFence() nothrow @nogc;
270+
271+
/**
272+
* Converts a shared lvalue to a non-shared lvalue.
273+
*
274+
* This functions allows to treat a shared lvalue as if it was thread-local.
275+
* It is useful to avoid overhead of atomic operations when access to shared data
276+
* is known to be within one thread (i.e. always under a lock).
277+
* ---
278+
* shared static int i;
279+
*
280+
* // i is never used outside of synchronized {} blocks...
281+
*
282+
* synchronized
283+
* {
284+
* ++i; // ERROR: cannot directly modify shared lvalue
285+
*
286+
* atomicOp!"+="(i, 1); // possible overhead
287+
*
288+
* // Directly modify i
289+
* assumeUnshared(i) += 1;
290+
* // or:
291+
* ++assumeUnshared(i);
292+
* // or:
293+
* i.assumeUnshared += 1;
294+
* }
295+
* ---
296+
* Usage of this function is restricted to allowing limited lvalue access to shared instances of
297+
* primitive and POD types (e.g. direct use of operators), thus it is not defined for classes.
298+
*
299+
* Note: this function does not perform any ordering.
300+
*
301+
* Note: assumeUnshared is a special-purpose primitive and should be used with care. When accessing
302+
* shared variables both inside and outside of synchronized blocks, atomic operations should be
303+
* used instead.
304+
*
305+
* Params:
306+
* val = the shared lvalue.
307+
*
308+
* Returns:
309+
* The non-shared lvalue.
310+
*/
311+
ref T assumeUnshared(T)(ref shared T val) @system @nogc pure nothrow
312+
if(!is(T == class) && !is(T == interface))
313+
{
314+
return *cast(T*) &val;
315+
}
316+
317+
/// ditto
318+
ref immutable(T) assumeUnshared(T)(ref immutable(T) val) @safe @nogc pure nothrow
319+
{
320+
return val;
321+
}
270322
}
271323
else version( AsmX86_32 )
272324
{
@@ -1409,6 +1461,26 @@ if(__traits(isFloating, T))
14091461
}
14101462
}
14111463

1464+
// assumeLocal is architecture-independent: it is just a cast
1465+
ref auto assumeLocal(T)( ref shared T val ) @trusted pure nothrow
1466+
if( !is( T == class ) )
1467+
{
1468+
return *cast(T*) &val;
1469+
}
1470+
1471+
// assumeUnshared is architecture-independent: it is just a cast
1472+
ref auto assumeUnshared(T)(ref shared T val) @system @nogc pure nothrow
1473+
if(!is(T == class) && !is(T == interface))
1474+
{
1475+
return *cast(T*) &val;
1476+
}
1477+
1478+
// immutable is implicitly unshared
1479+
ref auto assumeUnshared(T)(ref immutable(T) val) @safe @nogc pure nothrow
1480+
{
1481+
return val;
1482+
}
1483+
14121484
////////////////////////////////////////////////////////////////////////////////
14131485
// Unit Tests
14141486
////////////////////////////////////////////////////////////////////////////////
@@ -1711,4 +1783,81 @@ version( unittest )
17111783
shared NoIndirections n;
17121784
static assert(is(typeof(atomicLoad(n)) == NoIndirections));
17131785
}
1786+
1787+
pure nothrow @nogc @system unittest
1788+
{
1789+
int base = 0;
1790+
shared int atom = 0;
1791+
1792+
// only accept shared lvalues
1793+
static assert(!is(typeof(assumeUnshared(base))));
1794+
static assert(!is(typeof(assumeUnshared(cast(shared)base))));
1795+
1796+
++assumeUnshared(atom);
1797+
assert(atomicLoad!(MemoryOrder.raw)(atom) == 1);
1798+
}
1799+
1800+
pure nothrow @nogc @system unittest
1801+
{
1802+
shared const int catom = 0;
1803+
shared immutable int iatom = 0;
1804+
// allow const
1805+
static assert(is(typeof(assumeUnshared(catom))));
1806+
static assert(is(typeof(assumeUnshared(iatom))));
1807+
// preserve const
1808+
static assert(!is(typeof(++assumeUnshared(catom))));
1809+
static assert(!is(typeof(++assumeUnshared(iatom))));
1810+
}
1811+
1812+
pure nothrow @nogc @system unittest
1813+
{
1814+
class Klass {}
1815+
1816+
Klass c1;
1817+
shared Klass c2;
1818+
1819+
// don't accept class instances
1820+
static assert(!is(typeof(assumeUnshared(c1))));
1821+
static assert(!is(typeof(assumeUnshared(c2))));
1822+
}
1823+
1824+
pure nothrow @nogc @system unittest
1825+
{
1826+
interface Interface {}
1827+
Interface i1;
1828+
shared Interface i2;
1829+
1830+
// don't accept interfaces
1831+
static assert(!is(typeof(assumeUnshared(i1))));
1832+
static assert(!is(typeof(assumeUnshared(i2))));
1833+
}
1834+
1835+
pure nothrow @nogc @system unittest
1836+
{
1837+
// test assumeShared with inout
1838+
shared struct S
1839+
{
1840+
int atom = 0;
1841+
1842+
@property ref get() inout
1843+
{
1844+
return atom.assumeUnshared;
1845+
}
1846+
}
1847+
1848+
shared S sm;
1849+
shared const S sc;
1850+
shared immutable S si;
1851+
1852+
static assert(is(typeof(sm.get) == int));
1853+
static assert(is(typeof(sc.get) == const(int)));
1854+
static assert(is(typeof(si.get) == immutable(int)));
1855+
1856+
static assert( is(typeof(++sm.get)));
1857+
static assert(!is(typeof(++sc.get)));
1858+
static assert(!is(typeof(++si.get)));
1859+
1860+
sm.get += 10;
1861+
assert(atomicLoad!(MemoryOrder.raw)(sm.atom) == 10);
1862+
}
17141863
}

0 commit comments

Comments
 (0)
This repository has been archived.