diff -r 000000000000 -r 89d6a7a84779 Symbian3/SDK/Source/GUID-6590B534-D976-5305-BE95-48DD05120DFB.dita --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Symbian3/SDK/Source/GUID-6590B534-D976-5305-BE95-48DD05120DFB.dita Thu Jan 21 18:18:20 2010 +0000 @@ -0,0 +1,679 @@ + + + + + +Miscellaneous +Topics + +
Poll using +select

The select() function call provides functionality +to scan descriptors for a ready event. The select() call +requires the system to scan through a bit mask of a file descriptor set against +its list of open descriptors to check for ready events, only stopping when +it reaches a maximum descriptor value. For a system with a relatively small +number of open descriptors this is quite efficient but for a large amount +of descriptors can be overly burdensome.

The Symbian P.I.P.S. libraries +are not expected to be dealing with a very large number of file descriptors +and so select() should be satisfactory for any applications +on a phone.

Note: P.I.P.S. does not support the poll() function.

Monitoring two pipes using +select()

The following code segment shows the usage of the select() function:

Int main(int argc, char **argv) +{ + FILE* ChildProcessStream1; + FILE* ChildProcessStream2; + int ChildProcessFD1; + int ChildProcessFD2; + fd_set SelectFDs; + int MaxFD; + struct timeval timeout; + int Ret; + + //Create child process 1 using popen(). + ChildProcessStream1 = popen("/root/PortDoc/Example7_c/Symbian/Child/ChildProg", "r"); + if(ChildProcessStream1 == NULL) + { + printf("\n Failure to create child process 1 with popen()\n"); + return EXIT_FAILURE; + } + + //Create child process 2 using popen(). + ChildProcessStream2 = popen("/root/PortDoc/Example7_c/Symbian/Child/ChildProg", "r"); + if(ChildProcessStream2 == NULL) + { + printf("\n Failure to create child process 2 with popen()\n"); + return EXIT_FAILURE; + } + + //Convert streams to file descriptors + ChildProcessFD1 = fileno(ChildProcessStream1); + ChildProcessFD2 = fileno(ChildProcessStream2); + + //Setup the select set + FD_ZERO(&SelectFDs); + FD_SET(ChildProcessFD1, &SelectFDs); + MaxFD = ChildProcessFD1; + FD_SET(ChildProcessFD2, &SelectFDs); + + //Calculate the largest Descriptor + if (ChildProcessFD2 > MaxFD) + MaxFD = ChildProcessFD2; + + //Setup a time out value in case neither return in a sufficient time + timeout.tv_sec = 3; + timeout.tv_usec = 0; + + //Issue select request + Ret = select(MaxFD + 1, &SelectFDs, NULL, NULL, &timeout); + if (Ret == -1) + { + //Error occurred + printf("\nCould not poll, error=%d",errno); + return EXIT_FAILURE; + } + else if (Ret == 0) + { + //Timed out + printf("\nTimed Out"); + } + else + { + //Create a receive buffer, and zero contents before receiving. + Char RxBuffer[100]; + memset(RxBuffer,0,sizeof(RxBuffer)); + + if (FD_ISSET(ChildProcessFD1, &SelectFDs)) + { + //Wait for data from child process 1. Child sends a string. + Int nbytes = read(ChildProcessFD1,RxBuffer,sizeof(RxBuffer)); + printf("\nMessage Received from Child1 First =%s",RxBuffer); + } + else if (FD_ISSET(ChildProcessFD2, &SelectFDs)) + { + //Wait for data from child process 2. Child sends a string. + Int nbytes = read(ChildProcessFD2,RxBuffer,sizeof(RxBuffer)); + printf("\nMessage Received from Child2 First =%s",RxBuffer); + } + } + + //Wait for Child Process to complete + pclose(ChildProcessStream1); + pclose(ChildProcessStream2); + + return EXIT_SUCCESS; +}
+
Socket IOCtl +options

The underlying implementation of sockets on Symbian platform +imposes some restrictions on the socket options available in P.I.P.S. and +has also resulted in some new non-standard options to be created.

The +introduction of multi-homing (single link, multiple IP addresses) on Symbian +phones and the various methods of connecting to networks, such as Wi-Fi and +3G, with their varying degrees of cost to the user have made it important +to be able to choose which interface or access point is used to route socket +traffic. The Symbian RConnection class provides this functionality, +and is exposed in P.I.P.S. using some extra IOCtl options.

The list +of socket options available in P.I.P.S. are as follows:

+ + + +

Socket Option

+

New

+

Description

+
+ +

SIOCADDRT

+

Yes

+

Adds an entry to the interface routing table using the parameters +in the rtentry structure.

+
+ +

SIOCATMARK

+

No

+

Determines whether the read pointer is currently pointing to the +logical mark in the data stream, testing whether the next read will be Out-of-Band +data or not.

+
+ +

SIOCDELRT

+

Yes

+

Deletes an entry from the interface routing table using the parameters +in the rtentry structure.

+
+ +

SIOCGIFACTIVECONF

+

Yes

+

Gets a list of interfaces/access points started by P.I.P.S. in an ifconf structure.

+
+ +

SIOCGIFADDR

+

Yes

+

Gets the interface address. This is valid only for sockets with +address family AF_INET.

+
+ +

SIOCGIFCONF

+

No

+

Gets a list of available interfaces/access points in an ifconf structure.

+
+ +

SIOCGIFHWADDR

+

Yes

+

Gets the interface hardware address in an ifreq structure.

+
+ +

SIOCGIFINDEX

+

Yes

+

Sets the index of an interface/access point from a name in an ifreq structure.

+
+ +

SIOCGIFNUM

+

Yes

+

Return the total number of IP interfaces configured in the system.

+
+ +

SIOCIFACTIVESTART

+

Yes

+

Attempts to start a sub-connection on an available interface/access +point using the parameters in an ifreq structure.

+
+ +

SIOCIFSTART

+

Yes

+

Attempts to start an interface/access point using the parameters +in an ifreq structure.

+
+ +

SIOCIFSTOP

+

Yes

+

Stops a previously started interface or sub-connection.

+
+ +

SIOCSIFNAME

+

No

+

Sets the desired interface/access point name to start in an ifreq structure.

+
+ + +

The follow code for a function shows how to start an interface +called "3G Access Point" and return the created socket.

int opensocket() +{ + int Sock; + struct ifreq Ifr; + char AccessPoint[]="3G Access Point"; + + //Open the socket + Sock = socket(AF_INET, SOCK_STREAM, 0); + if (Sock < 0) + { + printf("\nCannot open socket, error=%d",errno); + return -1; + } + + //Set up the interface request structure + bzero(&Ifr, sizeof(Ifr)); + strcpy(Ifr.ifr_name, AccessPoint); + + //Set the requested interface name + if (ioctl(Sock, SIOCSIFNAME, &Ifr)) + { + printf("\nCannot set the interface name, error=%d",errno); + close(Sock); + return -1; + } + + //Start the interface + if (ioctl(Sock, SIOCIFSTART, &Ifr)) + { + printf("\nCannot start the interface, error=%d",errno); + close(Sock); + return -1; + } + + //Return the opened socket + return Sock; +}
+
Mathematical +functions

Symbian platform does not have any support for long doubles +so any P.I.P.S. programs which call long double versions of APIs will actually +invoke the double version of the API.

Symbian platform supports the +use of a hardware floating point co-processor, however not all phones incorporate +an FPU (Floating Point Unit) and rely on software emulation of floating point +operations. Phones and computers equipped with an FPU provide faster and more +accurate floating point operations.

Symbian platform does not support +complex numbers so the P.I.P.S. libraries are not able to offer the POSIX +complex number APIs.

Note: The mathematical functions are +included in the libm.dll file.

+
Error handling +and cleanup

It is important that Symbian platform error codes do +not reach any ported application code. P.I.P.S. logically maps the native +OS error codes with the corresponding POSIX errno values +as per the standard. So, ported programs will not usually have to alter their +error checking/handling.

Mapping +P.I.P.S. error codes to Symbian platform error codes

Porting your +application to Symbian platform requires 'translating' Symbian platform error +codes to POSIX error codes. User::Leaves() from native +Symbian APIs are trapped in P.I.P.S.. Calls to P.I.P.S. APIs from user code +need not be wrapped in TRAP s.

Occasionally +errors may be generated by the underlying Symbian platform that cannot be +translated to POSIX error codes, in which case the error variable errno will +be out of the usual range of values, above the maximum value of __EMAXERRNO or 124.

The +Symbian platform error code can be calculated using the following formula:

Symbian Error Code = -(errno - __EMAXERRNO)

Error +codes are defined in the errno.h file.

+
System logger

P.I.P.S. +does not supply a system logger for use with openlog(), syslog() and closelog(). +Instead, a rudimentary selection of functions which log to a file can be written +as demonstrated by the following example.

//define maximum length of identifier +#define SysLogMax 80 + +//logging file and identifier +FILE* fSysLog = NULL; +char fSysLogIdent[SysLogMax]; + +//close the log file +void my_closelog() +{ + //close the log file if it is open + if (fSysLog) + { + fclose(fSysLog); + fSysLog = NULL; + } + fSysLogIdent[0] = '\0'; +} + +//open a new log file +int my_openlog(const char *ident) +{ + //close the log file if it is open + if (fSysLog) + my_closelog(); + + //make the logging directory + mkdir("/syslog/", S_IWUSR | S_IRUSR | S_IXUSR); + + //open a new log file + fSysLog = fopen("/syslog/syslog.log", "a"); + + //return if the log file did not open + if (!fSysLog) + return -1; + + //set the identifier + if (!ident) + fSysLogIdent[0] = '\0'; + else + strncpy(fSysLogIdent, ident, SysLogMax); + + return 0; +} + +//output a string to the log file with a variable argument list +void my_vsyslog(const char *format, va_list formatlist) +{ + //open a log file if one does not exist + if (!fSysLog) + { + my_openlog(NULL); + } + + //check if there is a log file + if (fSysLog) + { + //print out the logging identifier if one exists + if (strlen(fSysLogIdent)) + { + fprintf(fSysLog, "%s ", fSysLogIdent); + } + + //print out the logging string + vfprintf(fSysLog, format, formatlist); + fprintf(fSysLog, "\r\n"); + } +} + +//output a string to the log file +void my_syslog(const char *format, ...) +{ + //create the variable argument list + va_list formatlist; + va_start(formatlist, format); + my_vsyslog(format, formatlist); + va_end(formatlist); +} + + +int main(int argc, char **argv) +{ + //open the log file + my_openlog("test"); + + //log a line + my_syslog("testing logging of the error number : %d", errno); + + //close the log + my_closelog(); + + return EXIT_SUCCESS; +}
+
Pthread barriers, +rwlocks and spinlocks

At present P.I.P.S. does not provide Pthread +barriers, rwlocks or spinlocks, but there are techniques which can be used +to implement the functionality using semaphores, mutexes and conditional variables.

The +following code sample (originally taken from http://heather.cs.ucdavis.edu/matloff/public_html/158/PLN/ParProcIntro.pdf) +demonstrates an implementation of a simple Pthread barrier.

struct barrier_t +{ + //number of nodes to synchronise + int nodes; + //two counts to avoid race conditions + int count[2]; + //which count to use + int whichcount; + //mutex to lock + pthread_mutex_t lock; + //condition to lock + pthread_cond_t cv; +}; + +//initialize a barrier +void InitBarrier(struct barrier_t* PB, int nodes) +{ + PB->nodes = nodes; + PB->count[0] = 0; + PB->count[1] = 0; + PB->whichcount = 0; + pthread_mutex_init(&PB->lock, NULL); + pthread_cond_init(&PB->cv, NULL); +} + +//destroy a barrier +void DestroyBarrier(struct barrier_t* PB) +{ + pthread_mutex_destroy(&PB->lock); + pthread_cond_destroy(&PB->cv); +} + +//wait for a barrier +void WaitBarrier(struct barrier_t* PB) +{ + int WhichCount, Count; + + //which counter variable to use + WhichCount = PB->whichcount; + + //lock the mutex + pthread_mutex_lock(&PB->lock); + + //get the count of nodes + Count = ++PB->count[WhichCount]; + + //test whether it should block + if (Count < PB->nodes) + pthread_cond_wait(&PB->cv, &PB->lock); + else + { + //reset the counter + PB->count[WhichCount] = 0; + PB->whichcount = 1 - WhichCount; + + //release the wait + pthread_cond_broadcast(&PB->cv); + } + + //unlock the threads + pthread_mutex_unlock(&PB->lock); +}

The following code was posted by Michael M. Lampkin as an +open source implementation of Pthread spin threads.

/********************************************************************** +BETA User Space spinlocks for POSIX systems lacking this functionality. +Copyright ©) 2003-2006 Michael M. Lampkin +Contact at michael.lampkin<at>ieee.org +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License version 2 as +published by the Free Software Foundation. +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. +You should have received a copy of the GNU General Public License +version 2 along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 + +**********************************************************************/ + +#define _POSIX_C_SOURCE 200112L +#define _XOPEN_SOURCE 600 + +#define SPINLOCK_SPIN_MAX 50 + +/** + Need this "unique" value that we can use to take any spinlock + that has been initialized and identify attempts to call init + multiple times without corresponding calls to destroy. A hard + coded value should be fine though still a 1 in 4 billion chance + of collision with random data in un-inited spinlock. +**/ + +static long int spin_magic = 0x2FCD51F9L; + +/** + The spinlock structure which should NEVER be manipulated + by user code. + owner: + a pthread_t var indicating the current owner of the + spinlock or filled with 0's if not owned + mutex: + the primary mutex that any incoming threads will spin on + and attempt to obtain. + magic: + a field to hold a sentinel value indicating if the spinlock + is initialized. +**/ + +typedef struct +{ + pthread_t owner; + pthread_mutex_t mutex; + long int magic; +} +spinlock; + +/** + Function: spinlock_init + Description: + Initializes and allocates system resources to a + spinlock structure. + Parameters: + spin - a pointer to the spinlock structure to + be initialized. + pshared - either PTHREAD_PROCESS_PRIVATE or + PTHREAD_PROCESS_SHARED. If the system does not + support process shared mutexes or an unknown value + is given then defaults internally to a private type + with no error. +**/ + +int spinlock_init( spinlock * spin, int pshared ) +{ + int result; + pthread_mutexattr_t attr; + + /* If already inited... race condition with destroy */ + if ( NULL == spin ) + { + return EINVAL; + } + + if ( spin_magic == spin->magic ) + { + return EBUSY; + } + + ( void ) memset( & spin->owner, 0, sizeof( pthread_t ) ); + + /* Set our process sharing attribute - default to PRIVATE */ + result = pthread_mutexattr_init( & attr ); + + if ( 0 == result ) + { + if ( 0 < sysconf( _SC_THREAD_PROCESS_SHARED ) ) + { + if( PTHREAD_PROCESS_SHARED == pshared ) + { + result = pthread_mutexattr_setpshared( & attr, pshared ); + } + else + { + result = pthread_mutexattr_setpshared( & attr, PTHREAD_PROCESS_PRIVATE ); + } + } + } + + /* Need to add this to prevent recursive mutex default on some sys */ + if ( 0 == result ) + { + result = pthread_mutexattr_settype( & attr, PTHREAD_MUTEX_ERRORCHECK ); + } + + /* The following is a race against simultaneous calls to init */ + if ( 0 == result ) + { + result = pthread_mutex_init( & spin->mutex, & attr ); + } + + if ( 0 == result ) + { + spin->magic = spin_magic; + } + + ( void ) pthread_mutexattr_destroy( & attr ); + return result; +} + +/** + Function: spinlock_destroy + Description: + Releases system resources allocated to a spinlock + structure during initializion. + Parameters: + spin - a pointer to a previously initialized but + not destroyed spinlock. +**/ +int spinlock_destroy( spinlock * spin ) +{ + int result; + + if ( NULL == spin || spin_magic != spin->magic ) + { + return EINVAL; + } + + if ( 0 != ( result = pthread_mutex_destroy( & spin->mutex ) ) ) + { + return result; + } + + ( void ) memset( & spin->owner, 0, sizeof( pthread_t ) ); + + /** + A return of EINVAL on destroy means another thread is + also destroying. Ignore it. + **/ + spin->magic = 0; + + return 0; +} + +/** + Function: spinlock_lock + Description: + Attempts to acquire exclusive access to the specified + spinlock. If the spinlock is already owned then begin + spinning until ownership is obtained. + + Parameters: + spin - a pointer to an initialized spinlock. +**/ +int spinlock_lock( spinlock * spin ) +{ + pthread_t self; + int result; + int spin_count; + + if ( NULL == spin || spin_magic != spin->magic ) + { + return EINVAL; + } + + self = pthread_self( ); + if ( 0 == memcmp( & spin->owner, & self, sizeof( pthread_t ) ) ) + { + return EDEADLK; + } + + for ( ; 0 != ( result = pthread_mutex_trylock( & spin->mutex ) ) ; ) + { + if ( EBUSY == result ) + { + ++ spin_count; + + if ( SPINLOCK_SPIN_MAX == spin_count ) + { + ( void ) sched_yield( ); + spin_count = 0; + } + } + else + { + /* Destroy occurred on us... */ + return EINVAL; + } + } + + ( void ) memcpy( & spin->owner, & self, sizeof( pthread_t ) ); + return result; +} + +/**
+
Command line +shell

Symbian platform phones do not have a command line shell +as standard. P.I.P.S. does however support the stdin(), stdout() and stderr() standard +streams, enabling parent processes to redirect a child's standard streams +for the exchange of data. Without explicitly redirecting the standard streams, +the default is for each to be redirected to the /dev/null directory. +The P.I.P.S. system() function does not create a shell +for a new program as in most POSIX implementations, however, it will start +a program and return the program's exit value.

+
User interfaces

Most +POSIX based systems interact with a windowing system such as X Windows and +libraries such as GTK. P.I.P.S., however, does not have its own UI libraries, +so any P.I.P.S. based applications that require UI functionality must rely +on the UI from the device manufacturer. As a consequence, for any UI program +that uses P.I.P.S., there must be an interaction between Symbian platform +native C++ and P.I.P.S. C code.

+
One Definition +Rule - warning

Standard C++ states that the One Definition +Rule (ODR) must be maintained within a program.

Symbian +platform can neither check (without significant modifications) that the ODR +is violated nor use the technique called symbol pre-emption to ensure that +the ODR is enforced.

Therefore, you must take care and must not assume +that there is only one copy of the symbol (that is, all instances of the same +symbol will have the same address) across all DLLs within a program.

+
\ No newline at end of file