×

Discussion Board

Results 1 to 13 of 13
  1. #1
    Registered User
    Join Date
    Mar 2006
    Posts
    19

    Dll::Tls(), porting from 2nd to 3rd edition

    Hi,

    I am porting a huge code base from S60 2nd edition SDK to 3rd edition. The linker complains that Dll::Tls() is an unreferenced symbol, and the documentation for 3rd edition states that the Dll class is no longer supported.

    What can I use as an alternative, or how can I fix the linker error? Thanks.


    ::EDIT::

    Well I found out that I had to include 'edllstub.lib' before 'euser.lib', this seems to have only changed the linker error. Now I'm getting errors inside of the SDK!

    Code:
    mwldsym2.exe: Undefined symbol: '__E32Dll'
    mwldsym2.exe: referenced from 'void * Dll::Tls(void) (?Tls@Dll@@SAPAXXZ)' in up_dll_tls.cpp:28 (edllstub.lib)
    Any push in the right direction would be most helpful. Thanks.
    Last edited by MethodSolutions; 2006-03-10 at 20:04.

  2. #2
    Nokia Developer Expert
    Join Date
    Jul 2003
    Location
    Vancouver, Canada
    Posts
    220

    Re: Dll::Tls(), porting from 2nd to 3rd edition

    I recommend that you look at the project in s60 3.0 SDK located at
    \Symbian\9.1\S60_3rd\examples\Base\ThreadsAndProcesses\TLS1

    This should help you understand how TLS works for 3.0 devices and what needs to be linked against.

    You will need the following missing file from the sdk and place it in \epoc32\include

    NOTE: I wouldn't expect DLL::Tls() etc.. to work in an .exe as it is specific to DLLs. In anycase you don't need it in an exe as it supports global data.

    Hope this helps

    this file needs to be saved named commonframework.h
    Code:
    // CommonFramework.h
    //
    // Copyright (c) 2000 Symbian Ltd.  All rights reserved.
    
    
    #ifndef __CommonFramework_H
    #define __CommonFramework_H
    
    #include <e32base.h>
    #include <e32cons.h>
    
    _LIT(KTxtEPOC32EX,"EXAMPLES");
    _LIT(KTxtExampleCode,"Symbian OS Example Code");
    _LIT(KFormatFailed,"failed: leave code=%d");
    _LIT(KTxtOK,"ok");
    _LIT(KTxtPressAnyKey," [press any key]");
    
    // public
    LOCAL_D CConsoleBase* console; // write all your messages to this
    LOCAL_C void doExampleL(); // code this function for the real example
    
    // private
    LOCAL_C void callExampleL(); // initialize with cleanup stack, then do example
    
    GLDEF_C TInt E32Main() // main function called by E32
        {
    	__UHEAP_MARK;
    	CTrapCleanup* cleanup=CTrapCleanup::New(); // get clean-up stack
    	TRAPD(error,callExampleL()); // more initialization, then do example
    	__ASSERT_ALWAYS(!error,User::Panic(KTxtEPOC32EX,error));
    	delete cleanup; // destroy clean-up stack
    	__UHEAP_MARKEND;
    	return 0; // and return
        }
    
    LOCAL_C void callExampleL() // initialize and call example code under cleanup stack
        {
    	console=Console::NewL(KTxtExampleCode,TSize(KConsFullScreen,KConsFullScreen));
    	CleanupStack::PushL(console);
    	TRAPD(error,doExampleL()); // perform example function
    	if (error)
    		console->Printf(KFormatFailed, error);
    	else
    		console->Printf(KTxtOK);
    	console->Printf(KTxtPressAnyKey);
    	console->Getch(); // get and ignore character
    	CleanupStack::PopAndDestroy(); // close console
        }
    
    #endif
    Last edited by billbonney; 2006-03-11 at 00:39.

  3. #3
    Regular Contributor
    Join Date
    Mar 2006
    Posts
    81

    Re: Dll::Tls(), porting from 2nd to 3rd edition

    I had the exact same problem and was left scratching my head for a while.
    The SDK documentation is totally misleading: the DLL class appears to be still implemented in Euser.dll

    The problem you've got is that in earlier OS versions your application WAS a dll so using DLL::Tls() was perfectly valid. In OS 9 your application is an EXE and therefore you shouldn't be using the DLL class at all! Just declare whatever pointer you were storing in the TLS as a global pointer. This compiles/links/works on winscw and compiles/links for gcce. I don't have a device to test with so I don't know if it actually works on a device, but it should do I guess.

  4. #4
    Regular Contributor
    Join Date
    May 2005
    Location
    Brasov, Romania
    Posts
    431

    Re: Dll::Tls(), porting from 2nd to 3rd edition

    Implement your own Dll-like class:
    Code:
    #define MAX_NR_OF_THREADS 5
    
    struct TMyDllData
    {
    	TMyDllData():crtThreadId(0),crtThreadPtrData(0)
    	{}
    	TThreadId	crtThreadId;
    	TAny*		crtThreadPtrData;
    };
    
    TMyDllData arrDllData[MAX_NR_OF_THREADS];
    
    TInt MyDll::SetTls(TAny* aPtr)
    {
    	RThread crtThread;
    	TThreadId crtId = crtThread.Id();
    
    	TInt crtThreadPos = 0;
    	TInt usedCnt = 0;
    
    	//pack that pointer
    	for(crtThreadPos = 0; crtThreadPos < MAX_NR_OF_THREADS; crtThreadPos++)
    	{
    		if(arrDllData[crtThreadPos].crtThreadId)
    		{
    			if(arrDllData[crtThreadPos].crtThreadId == crtId)
    			{
    				arrDllData[crtThreadPos].crtThreadPtrData = aPtr;
    				//it was set, now return
    				return 1;
    			}
    			usedCnt++;
    		}
    	}
    
    	//this thread id is not set, must set it
    	if(crtThreadPos == MAX_NR_OF_THREADS)
    	{
    		__ASSERT_SIMPLE__(usedCnt < MAX_NR_OF_THREADS);
    		arrDllData[usedCnt].crtThreadId = crtId;
    		arrDllData[usedCnt].crtThreadPtrData = aPtr;
    	}
    
    	return 1;
    }
    
    TAny* MyDll::Tls()
    {
    	RThread crtThread;
    	TThreadId crtId = crtThread.Id();
    
    	TAny* returnPtr = NULL;
    
    	TInt crtThreadPos = 0;
    
    	//unpack that pointer
    	for(crtThreadPos = 0; crtThreadPos < MAX_NR_OF_THREADS; crtThreadPos++)
    	{
    		if(arrDllData[crtThreadPos].crtThreadId == crtId)
    		{
    			returnPtr = arrDllData[crtThreadPos].crtThreadPtrData;
    			break;
    		}
    	}
    
    	return returnPtr;
    }

  5. #5
    Nokia Developer Moderator
    Join Date
    Feb 2006
    Location
    Oslo, Norway
    Posts
    28,689

    Re: Dll::Tls(), porting from 2nd to 3rd edition

    For application .dlls the preferred way for storing global data has been CCoeStatic so far, which also seems to work on 3rd ed.

  6. #6
    Regular Contributor
    Join Date
    May 2005
    Location
    Brasov, Romania
    Posts
    431

    Re: Dll::Tls(), porting from 2nd to 3rd edition

    Okay, but you have this support also for separate threads other than the main one?

  7. #7
    Registered User
    Join Date
    Jul 2003
    Posts
    190

    Re: Dll::Tls(), porting from 2nd to 3rd edition

    Anyway, I don't know why Tls() was part of Dll class, when threads (and their local storage) is not logically tied to Dll's.
    I can have multi-thread application also in exe, and I'd like to use thread local storage in exe, but it works only in DLL's.
    Does this make sense?

  8. #8
    Nokia Developer Expert
    Join Date
    Jul 2003
    Location
    Vancouver, Canada
    Posts
    220

    Re: Dll::Tls(), porting from 2nd to 3rd edition

    You don't need TLS in an exe as you can have global writable data and use that as your 'Thread Local Storage'. Hence this is why it is tied to the DLL class as it's only required for threads created in DLLs.

  9. #9
    Nokia Developer Moderator
    Join Date
    Feb 2006
    Location
    Oslo, Norway
    Posts
    28,689

    Re: Dll::Tls(), porting from 2nd to 3rd edition

    You might find it interesting:
    (3rd ed SDK Help)Symbian OS v9.1/Symbian OS guide/Essential idioms/Static data
    it has been a bit renewed.

  10. #10
    Nokia Developer Expert
    Join Date
    Jul 2003
    Location
    Vancouver, Canada
    Posts
    220

    Post Re: Dll::Tls(), porting from 2nd to 3rd edition

    and here's a link to the page on the web http://www.symbian.com/developer/tec...taticData.html

  11. #11
    Super Contributor
    Join Date
    Nov 2005
    Location
    London
    Posts
    584

    Re: Dll::Tls(), porting from 2nd to 3rd edition

    This is a helpful paper too, also on the Symbian site:

    http://www.symbian.com/developer/tec...InDLLsv1.1.pdf

  12. #12
    Registered User
    Join Date
    May 2006
    Posts
    1

    Re: Dll::Tls(), porting from 2nd to 3rd edition

    Quote Originally Posted by mike.b
    Anyway, I don't know why Tls() was part of Dll class, when threads (and their local storage) is not logically tied to Dll's.
    I can have multi-thread application also in exe, and I'd like to use thread local storage in exe, but it works only in DLL's.
    Does this make sense?
    This is a common misunderstanding. The thing to remember is each DLL gets its own unique TLS word per thread it runs in, hence the reason it's a member of DLL. If you think about it, this is obvious: one TLS word per thread shared amongst all the thousands of DLLs in the OS alone would not be any use to any one of them, even without considering the UI and third-party code.
    If you really want to have something TLS-like in your exe (i.e. a unique word per thread), you can always create a trivial helper DLL that just has two methods that call right through to Dll::Tls() and Dll::SetTls().

  13. #13
    Registered User
    Join Date
    Jun 2009
    Posts
    35

    Re: Dll::Tls(), porting from 2nd to 3rd edition

    This is an article I found in http://blog.sina.com.cn/s/blog_4c5ad0740100bs64.html which fully explained what the problem is.

    DLL can manage writable static data on a per-thread basis using thread-local storage, commonly known as ”TLS”. This allocates a single machine word of writable static data per thread for every DLL, regardless of whether the DLL uses it. Obviously, the memory overhead is far less significant than allocating a 4 KB chunk for each DLL which uses static data. However, the price of using TLS instead of Direct Memory Access is performance; data is retrieved from TLS about 30 times slower than direct access, because the lookup involves a context switch to the kernel in order to access the data. Thread-local storage is usually initialized when the DLL is attached to a thread within the DLL entry point, E32Dll().Typically, code is added to construct the struct containing the global data and store it in thread-local storage using the static function Dll::SetTLS().To access the data, you should use the static function Dll::Tls(). This will return a TAny* which can be cast and used to access the data. For simplicity, you may wish to provide a utility function, or set of functions, to access the data from a single point.

    TLS is thread and DLL -specific so every DLL in a thread can use it without risk of mixups.
    Usage example

    // Create an object and store the pointer in TLS
    CSomeClass* object = CSomeClass::NewL();
    User::LeaveIfError( Dll::SetTls( object ) );
    // Get the object from TLS
    object = static_cast<CSomeClass*>( Dll::Tls() );
    // When done with the object, delete it and free TLS
    delete object;
    object = NULL;
    Dll::FreeTls();

    Note! The TLS does not take ownership of the object so the user is responsible for deleting it.


    Usage example in an EXE project

    The above code uses the static Dll class to access the TLS which means it only works in a DLL project. TLS can also be used in an EXE project, but through a different static class. UserSvr provides the same API to TLS except that it requires somekind of an id to the pointer being stored. The Dll class actually uses UserSvr to access TLS provinding the DLL module handle as the id. The same code example in an EXE project would look something like this:

    #include <e32svr.h> // For UserSvr

    // Define a handle. This has to be unique within the thread.

    const TInt KMyTlsHandle = 0xC0FFEE;

    // Create an object and store the pointer in TLS

    CSomeObject* object = CSomeObject::NewL();

    User::LeaveIfError( UserSvr:llSetTls( KMyTlsHandle, object ) );

    // Get the object from TLS

    object = static_cast<CSomeObject*>( UserSvr:llTls( KMyTlsHandle ) );

    // When done with the object, delete it and free TLS

    delete object;

    PS:转上面的目的主要是说说今天遇到的编译错误:

    在我使用自己写的Log的时候,出现以下错误,当然,里面用到了线程本地存储,我写的程序是exe的,当然不能使用 Dll::SetTls的形式了。按照以上方法修改就可以了。



    mwldsym2.exe: Undefined symbol: '__E32Dll'
    mwldsym2.exe: referenced from 'int Dll::SetTls(void *) (?SetTls@Dll@@SAHPAX@Z)'
    in up_dll_tls.cpp:19 (edllstub.lib)
    mwldsym2.exe: referenced from 'void * Dll::Tls(void) (?Tls@Dll@@SAPAXXZ)' in up_
    dll_tls.cpp:28 (edllstub.lib)

Similar Threads

  1. Replies: 8
    Last Post: 2008-10-15, 19:54
  2. Linking dll in S60 3rd edition - experts please help!
    By iulian_moldovan in forum Symbian Tools & SDKs
    Replies: 7
    Last Post: 2007-06-13, 18:41
  3. TTime : TInt64& Int64() problem in S60 3rd edition
    By iulian_moldovan in forum Symbian Tools & SDKs
    Replies: 3
    Last Post: 2006-01-24, 13:07
  4. OpenGL ES Support in S60 3rd Edition Beta SDK
    By choefele in forum Symbian Media (Closed)
    Replies: 2
    Last Post: 2005-12-14, 06:01

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  
×