Topic: Custom inheritable data/function attributes (for
Author: emuzychenko@gmail.com
Date: Fri, 16 Mar 2018 03:03:01 -0700 (PDT)
Raw View
------=_Part_686_70232112.1521194581856
Content-Type: multipart/alternative;
boundary="----=_Part_687_1893615824.1521194581856"
------=_Part_687_1893615824.1521194581856
Content-Type: text/plain; charset="UTF-8"
C++ supports very useful *const* attribute. It can be assigned to both data
and code (function). It is *inheritable* ('const' member of a base class is
still constant in derived classes, 'const' member function gets a 'const'
object). There is less useful *volatile* attribute, working the same way.
I think it is a good idea to have an ability to declare custom
(user-defined) *compile-time-only* attributes that can be assigned either
(or both) to data and/or code, make them inheritable, and define some usage
restrictions, like const/volatile do.
Example 1: in a parallel <https://en.wikipedia.org/wiki/Parallel_computing>
(multi-threaded) code with concurrent data access, an object can be shared
between several threads. To access the object safely, a thread must ensure mutual
exclusion <https://en.wikipedia.org/wiki/Mutual_exclusion> with other
threads, acquiring a *lock* (a mutex, semaphore, critical section etc.)
associated with the object. There are no problems accessing a single shared
object at a time. But if a thread needs to access several shared objects,
each of them protected with its own lock, a deadlock
<https://en.wikipedia.org/wiki/Deadlock> can occur. In spite of there is an
explicit association between the object and the protection lock, there is
no language feature to declare this association at compile time. So many
errors that may cause deadlocks are found at run-time only. There are
complex software instruments to analyze run-time code behavior while the
same work can easily be performed by a compiler at compile time.
Example 2: real-time <https://en.wikipedia.org/wiki/Real-time_computing>
programming (including embedded system programming). There is an important
code/data property like "can cause a long delay". It may be a code executed
too long, or accesses resources not available "momentarily" (disk or even
network files), or acquiring a protective lock for shared access; a data
that can be protected by a lock, or paged
<https://en.wikipedia.org/wiki/Paging> out, or need to be built. To avoid
undesired execution delays, or blocking
<https://en.wikipedia.org/wiki/Blocking_(computing)>, a real-time process
must not call such code or access such data. But there are no language
features to declare/check such code/data properties so many errors are very
hard to find.
Example 3: kernel-mode programming. OS kernels have some data objects that
can be accessed (or functions can be called) only with specified conditions
(for example, cannot be accessed/called from an interrupt handler). Errors
related to violation of such rules can be found only at run time.
Example 4: there can be "reliable" (checking all their arguments on every
call) and "unreliable" (relying on the caller) functions. Of course, a
reliable function can call either reliable or unreliable function but
unreliable function should not call another unreliable one.
All these code/data properties are *inheritable* by their nature:
- If a class requires mutual exclusion to access its objects, all
classes derived from (or including) this class may require it too (a
'data-to-data' inheritance).
- If a function can block
<https://en.wikipedia.org/wiki/Blocking_(computing)> thread execution,
all functions calling this function can block too (a 'code-to-code'
inheritance).
- If a function accesses an object protected by a lock, this function
can block thread execution (a 'data-to-code' inheritance).
- If a class has member functions than can block, access to class
objects can block too (a 'code-to-data' inheritance).
The proposal is to add language features allowing to declare and check
various code/data attributes.
For such idea, there should be three features:
- Attribute declaration, separate for code and data
- Attribute inheritance rules
- Attribute checking rules
Attributes used in a program can be (but not obligatory) declared in
advance:
attributes {
data:needs_lock_a, // Accessing code must hold mutex (lock) A
data:needs_lock_b, // Accessing code must hold mutex (lock) B
code:needs_lock_a, // Needs mutex (lock) A to be held by a caller
code:needs_lock_b, // Needs mutex (lock) B to be held by a caller
code:holds_lock_a, // Holds mutex (lock) A
code:holds_lock_b, // Holds mutex (lock) B
code:can_block, // Can block execution flow
code:realtime, // Real-time code that cannot be blocked
data:pageable, // Occupies non-locked memory that can be paged out
}
class attribute (cannot_be_accessed_from_interrupt_handler)
ResourceDescriptor {...};
int attribute (needs_lock_a) Count1;
int attribute (needs_lock_b) Count2;
void attribute (holds_lock_a) IncreaseCounter1 ();
void attribute (holds_lock_b) IncreaseCounter2 ();
Therefore, attribute type (data/code) can be derived implicitly from the
declaration/definition.
Inheritance rules should define the following:
- If an object is wrapped with another object, all data attributes are
inherited.
- If a function calls (explicitly) another function, the caller function
inherits all callee code attributes.
- If a function accesses an object, how code attributes are derived from
data attributes.
- If a class has a member function, object data attributes are derived
from function code attributes.
attribute_inheritance (<source>, <destination>)
attribute_inheritance (data:needs_lock_a, code:needs_lock_a) // Code
accessing the object must host lock A
attribute_inheritance (data:needs_lock_b, code:needs_lock_b) // Code
accessing the object must host lock B
attribute_inheritance (code:holds_lock_a || holds_lock_b, code:can_block)
// Code holding a lock can block the execution
attribute_inheritance (data:pageable, code:can_block) // Code accessing
pageable data can block the execution
Checking rules (assume that attribute names return boolean values):
attribute_check (code:realtime != code:can_block) // Realtime code is not
compatible with blocking code
attribute_check (!(code:holds_lock_b && code_needs_lock_a)) // If a code
holds lock B, it cannot hold lock A (prevent deadlocks)
Or there could be an operator like "get_attribute ()", returning attributes
of a class, object or function, to be used in a statement like assume().
Keywords and syntax used are for example only, actual implementation could
be completely different.
Such access control model can be used to implement various access rules
(for example, in cases where "mutable" cannot be used safely, or to mark
test/unfinished objects/functions that must not be accessed by production
code).
--
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/1c12a5bb-154e-431e-a064-73f2d3a8af9e%40isocpp.org.
------=_Part_687_1893615824.1521194581856
Content-Type: text/html; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable
<div dir=3D"ltr">C++ supports very useful <b>const</b> attribute. It can b=
e assigned to both data and code (function). It is <b>inheritable</b> ('=
;const' member of a base class is still constant in derived classes, &#=
39;const' member function gets a 'const' object). There is less=
useful <b>volatile</b> attribute, working the same way.<br><br>I think it =
is a good idea to have an ability to declare custom (user-defined) <b>compi=
le-time-only</b> attributes that can be assigned either (or both) to data a=
nd/or code, make them inheritable, and define some usage restrictions, like=
const/volatile do.<br><br>Example 1: in a <a href=3D"https://en.wikipedia.=
org/wiki/Parallel_computing">parallel</a> (multi-threaded) code with concur=
rent data access, an object can be shared between several threads. To acces=
s the object safely, a thread must ensure <a href=3D"https://en.wikipedia.o=
rg/wiki/Mutual_exclusion">mutual exclusion</a> with other threads, acquirin=
g a <b>lock</b> (a mutex, semaphore, critical section etc.) associated with=
the object. There are no problems accessing a single shared object at a ti=
me. But if a thread needs to access several shared objects, each of them pr=
otected with its own lock, a <a href=3D"https://en.wikipedia.org/wiki/Deadl=
ock">deadlock</a> can occur. In spite of there is an explicit association b=
etween the object and the protection lock, there is no language feature to =
declare this association at compile time. So many errors that may cause dea=
dlocks are found at run-time only. There are complex software instruments t=
o analyze run-time code behavior while the same work can easily be performe=
d by a compiler at compile time.<br><br>Example 2: <a href=3D"https://en.wi=
kipedia.org/wiki/Real-time_computing">real-time</a> programming (including =
embedded system programming). There is an important code/data property like=
"can cause a long delay". It may be a code executed too long, or=
accesses resources not available "momentarily" (disk or even net=
work files), or acquiring a protective lock for shared access; a data that =
can be protected by a lock, or <a href=3D"https://en.wikipedia.org/wiki/Pag=
ing">paged</a> out, or need to be built. To avoid undesired execution delay=
s, or <a href=3D"https://en.wikipedia.org/wiki/Blocking_(computing)">blocki=
ng</a>, a real-time process must not call such code or access such data. Bu=
t there are no language features to declare/check such code/data properties=
so many errors are very hard to find.<br><br>Example 3: kernel-mode progra=
mming. OS kernels have some data objects that can be accessed (or functions=
can be called) only with specified conditions (for example, cannot be acce=
ssed/called from an interrupt handler). Errors related to violation of such=
rules can be found only at run time.<br><br>Example 4: there can be "=
reliable" (checking all their arguments on every call) and "unrel=
iable" (relying on the caller) functions. Of course, a reliable functi=
on can call either reliable or unreliable function but unreliable function =
should not call another unreliable one.<br><br>All these code/data properti=
es are <b>inheritable</b> by their nature:<br><ul><li>If a class requires m=
utual exclusion to access its objects, all classes derived from (or includi=
ng) this class may require it too (a 'data-to-data' inheritance).</=
li><li>If a function can <a href=3D"https://en.wikipedia.org/wiki/Blocking_=
(computing)">block</a> thread execution, all functions calling this functio=
n can block too (a 'code-to-code' inheritance).</li><li>If a functi=
on accesses an object protected by a lock, this function can block thread e=
xecution (a 'data-to-code' inheritance).</li><li>If a class has mem=
ber functions than can block, access to class objects can block too (a '=
;code-to-data' inheritance).<br></li></ul>The proposal is to add langua=
ge features allowing to declare and check various code/data attributes.<br>=
<br>For such idea, there should be three features:<br><ul><li>Attribute dec=
laration, separate for code and data</li><li>Attribute inheritance rules</l=
i><li>Attribute checking rules<br></li></ul>Attributes used in a program ca=
n be (but not obligatory) declared in advance:<br><br>attributes {<br>=C2=
=A0 data:needs_lock_a, // Accessing code must hold mutex (lock) A<br>=C2=A0=
data:needs_lock_b, // Accessing code must hold mutex (lock) B<br>=C2=A0 co=
de:needs_lock_a, // Needs mutex (lock) A to be held by a caller<br>=C2=A0 c=
ode:needs_lock_b, // Needs mutex (lock) B to be held by a caller<br>=C2=A0 =
code:holds_lock_a, // Holds mutex (lock) A<br>=C2=A0 code:holds_lock_b, // =
Holds mutex (lock) B<br>=C2=A0 code:can_block, // Can block execution flow<=
br>=C2=A0 code:realtime, // Real-time code that cannot be blocked<br>=C2=A0=
data:pageable, // Occupies non-locked memory that can be paged out<br>}<br=
><br>class attribute (cannot_be_accessed_from_interrupt_handler) ResourceDe=
scriptor {...};<br>int attribute (needs_lock_a) Count1;<br>int attribute (n=
eeds_lock_b) Count2;<br>void attribute (holds_lock_a) IncreaseCounter1 ();<=
br>void attribute (holds_lock_b) IncreaseCounter2 ();<br><br>Therefore, att=
ribute type (data/code) can be derived implicitly from the declaration/defi=
nition.<br><br>Inheritance rules should define the following:<br><ul><li>If=
an object is wrapped with another object, all data attributes are inherite=
d.<br></li><li>If a function calls (explicitly) another function, the calle=
r function inherits all callee code attributes.<br></li><li>If a function a=
ccesses an object, how code attributes are derived from data attributes.</l=
i><li>If a class has a member function, object data attributes are derived =
from function code attributes.<br></li></ul>attribute_inheritance (<sour=
ce>, <destination>)<br><br>attribute_inheritance (data:needs_lock_=
a, code:needs_lock_a) // Code accessing the object must host lock A<br>attr=
ibute_inheritance (data:needs_lock_b, code:needs_lock_b) // Code accessing =
the object must host lock B<br>attribute_inheritance (code:holds_lock_a || =
holds_lock_b, code:can_block) // Code holding a lock can block the executio=
n<br>attribute_inheritance (data:pageable, code:can_block) // Code accessin=
g pageable data can block the execution<br><br>Checking rules (assume that =
attribute names return boolean values):<br><br>attribute_check (code:realti=
me !=3D code:can_block) // Realtime code is not compatible with blocking co=
de<br>attribute_check (!(code:holds_lock_b && code_needs_lock_a)) /=
/ If a code holds lock B, it cannot hold lock A (prevent deadlocks)<br><br>=
Or there could be an operator like "get_attribute ()", returning =
attributes of a class, object or function, to be used in a statement like a=
ssume().<br><br>Keywords and syntax used are for example only, actual imple=
mentation could be completely different.<br><br>Such access control model c=
an be used to implement various access rules (for example, in cases where &=
quot;mutable" cannot be used safely, or to mark test/unfinished object=
s/functions that must not be accessed by production code).<br></div>
<p></p>
-- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals" group.<br />
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to <a href=3D"mailto:std-proposals+unsubscribe@isocpp.org">std-proposa=
ls+unsubscribe@isocpp.org</a>.<br />
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org">std-proposals@isocpp.org</a>.<br />
To view this discussion on the web visit <a href=3D"https://groups.google.c=
om/a/isocpp.org/d/msgid/std-proposals/1c12a5bb-154e-431e-a064-73f2d3a8af9e%=
40isocpp.org?utm_medium=3Demail&utm_source=3Dfooter">https://groups.google.=
com/a/isocpp.org/d/msgid/std-proposals/1c12a5bb-154e-431e-a064-73f2d3a8af9e=
%40isocpp.org</a>.<br />
------=_Part_687_1893615824.1521194581856--
------=_Part_686_70232112.1521194581856--
.