www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Request: 'local' keyword for TLS support

reply Sean Kelly <sean f4.ca> writes:
I've found thread local storage to be nearly indispensable at times, and 
it seems awkward to do this via library routines in D, as the library 
calls are relatively slow and make this seem like a feature that has 
been tacked onto a language that was not designed to support 
multithreading.  I would like to propose a new keyword, 'local', that 
may be used as a modifier for static variables which indicates that the 
variable should have per-thread storage.  For reference, the Sun and 
Microsoft compilers currently have this feature via the __thread and 
__declspec keywords, and relevant documentation can be found on each. 
The salient portion of the MS docs is as follows:

	You must observe these guidelines when declaring thread local objects 
and variables:

	* You can apply the thread attribute only to data declarations and 
definitions, and classes that do not have member functions; thread 
cannot be used on function declarations or definitions.

	* The use of the thread attribute may interfere with delay loading of 
DLL imports.

	* You can specify the thread attribute only on data items with static 
storage duration. This includes global data objects (both static and 
extern), local static objects, and static data members of classes. You 
cannot declare automatic data objects with the thread attribute.

	* You must use the thread attribute for the declaration and the 
definition of a thread local object, whether the declaration and 
definition occur in the same file or separate files.

	* You cannot use the thread attribute as a type modifier.

	* Only POD classes may be instantiated using __declspec(thread). The 
thread attribute is ignored if no object is declared as part of the 
class declaration.

Assuming the compiler doesn't take over control of thread 
initialization, perhaps it would be sufficient to place this restriction 
upon the thread entry point in library code: the first line of this 
routine should be a fixed-size void array with a size parameter of 
RESERVED_LOCAL_SIZE.  For instance:

void entryPoint(void* p) {
     void[RESERVED_LOCAL_SIZE] tls_data;
     ...
}

An alternative would be for the compiler supply an entry point that 
accepts a delegate parameter.  Thus:

// internal (in runtime code)

extern (C) void compilerSuppliedEntryPoint(void* p) {
     // do whatever needs to be done
     (cast(void delegate()) p)();
}

// in standard library

extern (C) void compilerSuppliedEntryPoint(void*);

class Thread {
     void start() {
         // call compiler routine with run method as parameter
         beginthread( &compilerSuppliedEntryPoint, 0, &run );
     }

private void run() {
         // user thread entry point
     }
}
Jan 03 2006
parent reply "Kris" <fu bar.com> writes:
"Sean Kelly" <sean f4.ca> wrote ...
 I've found thread local storage to be nearly indispensable at times, and 
 it seems awkward to do this via library routines in D, as the library 
 calls are relatively slow and make this seem like a feature that has been 
 tacked onto a language that was not designed to support multithreading.  I 
 would like to propose a new keyword, 'local', that may be used as a 
 modifier for static variables which indicates that the variable should 
 have per-thread storage.  For reference, the Sun and Microsoft compilers 
 currently have this feature via the __thread and __declspec keywords, and 
 relevant documentation can be found on each. The salient portion of the MS 
 docs is as follows:

 You must observe these guidelines when declaring thread local objects and 
 variables:

 * You can apply the thread attribute only to data declarations and 
 definitions, and classes that do not have member functions; thread cannot 
 be used on function declarations or definitions.

 * The use of the thread attribute may interfere with delay loading of DLL 
 imports.

 * You can specify the thread attribute only on data items with static 
 storage duration. This includes global data objects (both static and 
 extern), local static objects, and static data members of classes. You 
 cannot declare automatic data objects with the thread attribute.

 * You must use the thread attribute for the declaration and the definition 
 of a thread local object, whether the declaration and definition occur in 
 the same file or separate files.

 * You cannot use the thread attribute as a type modifier.

 * Only POD classes may be instantiated using __declspec(thread). The 
 thread attribute is ignored if no object is declared as part of the class 
 declaration.

 Assuming the compiler doesn't take over control of thread initialization, 
 perhaps it would be sufficient to place this restriction upon the thread 
 entry point in library code: the first line of this routine should be a 
 fixed-size void array with a size parameter of RESERVED_LOCAL_SIZE.  For 
 instance:

 void entryPoint(void* p) {
     void[RESERVED_LOCAL_SIZE] tls_data;
     ...
 }

 An alternative would be for the compiler supply an entry point that 
 accepts a delegate parameter.  Thus:

 // internal (in runtime code)

 extern (C) void compilerSuppliedEntryPoint(void* p) {
     // do whatever needs to be done
     (cast(void delegate()) p)();
 }

 // in standard library

 extern (C) void compilerSuppliedEntryPoint(void*);

 class Thread {
     void start() {
         // call compiler routine with run method as parameter
         beginthread( &compilerSuppliedEntryPoint, 0, &run );
     }

 private void run() {
         // user thread entry point
     }
 }

I don't wish to confuse the waters, but isn't it far simpler to just extend the Thread class for such things? I use thread-locals a /lot/, and find the strategy of subclassing Thread to add thread-specific attributes to be perfectly suited. It does not require further support from the compiler, and is perfectly type-safe (no need to go cast()ing anywhere). True, one cannot subclass the initial 'main' thread, but I don't see that as much of an impediment? Does the subclassing strategy not satisfy the need, or not do so in a manner that's both convenient and non-fugly? - Kris
Jan 03 2006
parent reply Sean Kelly <sean f4.ca> writes:
Kris wrote:
 
 I don't wish to confuse the waters, but isn't it far simpler to just extend 
 the Thread class for such things?

Typically, yes. Though there are times when I think it's nice to have non-OO code that can manipulate thread local data, and I'd prefer to avoid library calls if possible. But I grant that this may not be sufficient reason to argue for a language addition.
 I use thread-locals a /lot/, and find the
 strategy of subclassing Thread to add thread-specific attributes to be 
 perfectly suited. It does not require further support from the compiler, and 
 is perfectly type-safe (no need to go cast()ing anywhere). True, one cannot 
 subclass the initial 'main' thread, but I don't see that as much of an 
 impediment?

It really isn't. There are a few cases where the inheritance method simply doesn't serve--typically when the main thread needs to access the data--but this perhaps isn't a huge issue.
 Does the subclassing strategy not satisfy the need, or not do so in a manner 
 that's both convenient and non-fugly?

I suppose my motivation for this is perhaps drawn from a desire to offer equivalent support for both OO and non-OO programming in D--this is largely why I added the TLS library calls in Ares as well. But whether such a desire warrants language support is questionable. Sean
Jan 03 2006
parent "Kris" <fu bar.com> writes:
"Sean Kelly" <sean f4.ca> wrote ..
 Kris wrote:
 Does the subclassing strategy not satisfy the need, or not do so in a 
 manner that's both convenient and non-fugly?

I suppose my motivation for this is perhaps drawn from a desire to offer equivalent support for both OO and non-OO programming in D--this is largely why I added the TLS library calls in Ares as well.

I now see what you're getting at. Thanks!
Jan 03 2006