Symbian3/SDK/Source/GUID-6590B534-D976-5305-BE95-48DD05120DFB.dita
changeset 0 89d6a7a84779
child 2 ebc84c812384
--- /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 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (c) 2007-2010 Nokia Corporation and/or its subsidiary(-ies) All rights reserved. -->
+<!-- This component and the accompanying materials are made available under the terms of the License 
+"Eclipse Public License v1.0" which accompanies this distribution, 
+and is available at the URL "http://www.eclipse.org/legal/epl-v10.html". -->
+<!-- Initial Contributors:
+    Nokia Corporation - initial contribution.
+Contributors: 
+-->
+<!DOCTYPE concept
+  PUBLIC "-//OASIS//DTD DITA Concept//EN" "concept.dtd">
+<concept id="GUID-6590B534-D976-5305-BE95-48DD05120DFB" xml:lang="en"><title>Miscellaneous
+Topics</title><prolog><metadata><keywords/></metadata></prolog><conbody>
+<ul>
+<li id="GUID-6830949E-0825-5E13-9B3E-86B5014F4B77"><p><xref href="GUID-6590B534-D976-5305-BE95-48DD05120DFB.dita#GUID-6590B534-D976-5305-BE95-48DD05120DFB/GUID-624B9EC6-7C8E-5408-AAF3-F799314B6D7A">Poll using select</xref>  </p> <ul>
+<li id="GUID-7E0FA15B-8AFB-59DD-B577-34905989D316"><p><xref href="GUID-6590B534-D976-5305-BE95-48DD05120DFB.dita#GUID-6590B534-D976-5305-BE95-48DD05120DFB/GUID-6B8931EB-7AB9-588C-B419-0CD4BA048397">Monitoring two pipes using select()</xref>  </p> </li>
+</ul> </li>
+<li id="GUID-245A31A4-4C38-54F4-9ACC-92285C12966E"><p><xref href="GUID-6590B534-D976-5305-BE95-48DD05120DFB.dita#GUID-6590B534-D976-5305-BE95-48DD05120DFB/GUID-7582B2CB-AAC8-5E41-ADE1-76C12B691E10">Socket IOCtl options</xref>  </p> </li>
+<li id="GUID-1A2BDA7D-2DE4-52AE-ACD3-12D1A6311A88"><p><xref href="GUID-6590B534-D976-5305-BE95-48DD05120DFB.dita#GUID-6590B534-D976-5305-BE95-48DD05120DFB/GUID-9BF9562E-5831-5A7F-90A1-87BDE1CFBA54">Mathematical functions</xref>  </p> </li>
+<li id="GUID-A6183A50-BFBA-573B-B2BC-68BE637D7DF5"><p><xref href="GUID-6590B534-D976-5305-BE95-48DD05120DFB.dita#GUID-6590B534-D976-5305-BE95-48DD05120DFB/GUID-DA65E8FA-E20B-5572-AEC9-20AB140DF33A">Error handling and cleanup</xref>  </p> <ul>
+<li id="GUID-ADB0AC3E-FB59-52DC-B151-A4551467CBA0"><p><xref href="GUID-6590B534-D976-5305-BE95-48DD05120DFB.dita#GUID-6590B534-D976-5305-BE95-48DD05120DFB/GUID-D8DB43BD-9D19-5A78-8E37-6699653D047A">Mapping P.I.P.S. error codes to Symbian platform error codes</xref>  </p> </li>
+</ul> </li>
+<li id="GUID-EA748131-29ED-5D32-B1C2-F948ABEA6584"><p><xref href="GUID-6590B534-D976-5305-BE95-48DD05120DFB.dita#GUID-6590B534-D976-5305-BE95-48DD05120DFB/GUID-CF52A59F-FD04-5043-A526-05545E11F0F5">System logger</xref>  </p> </li>
+<li id="GUID-1C98EDF4-C7BD-5CC8-90EB-D35B759280CD"><p><xref href="GUID-6590B534-D976-5305-BE95-48DD05120DFB.dita#GUID-6590B534-D976-5305-BE95-48DD05120DFB/GUID-8C951D9F-DE32-5201-90F2-45EB442F9FFC">Pthread barriers, rwlocks and spinlocks</xref>  </p> </li>
+<li id="GUID-AFB6D3DE-B1ED-51CF-B02D-BBF1958F6357"><p><xref href="GUID-6590B534-D976-5305-BE95-48DD05120DFB.dita#GUID-6590B534-D976-5305-BE95-48DD05120DFB/GUID-777FDBF9-4B80-5B58-88F3-E78DBDB89021">Command line shell</xref>  </p> </li>
+<li id="GUID-2357315B-21A6-5A9D-8D8D-B72043376F41"><p><xref href="GUID-6590B534-D976-5305-BE95-48DD05120DFB.dita#GUID-6590B534-D976-5305-BE95-48DD05120DFB/GUID-98FE0A61-A9F6-5216-A01F-A213F33D3173">User interfaces</xref>  </p> </li>
+<li id="GUID-EB745371-907B-595B-AD2F-0FB0B7991066"><p><xref href="GUID-6590B534-D976-5305-BE95-48DD05120DFB.dita#GUID-6590B534-D976-5305-BE95-48DD05120DFB/GUID-3CA8FF29-79B4-5D43-8A23-EDB136BF7A8F">One Definition Rule - warning</xref>  </p> </li>
+</ul>
+<section id="GUID-624B9EC6-7C8E-5408-AAF3-F799314B6D7A"><title>Poll using
+select</title> <p>The <xref href="GUID-8B4D4123-8146-3157-B171-28F71E0C8E4A.dita"><apiname>select()</apiname></xref> function call provides functionality
+to scan descriptors for a ready event. The <codeph>select()</codeph> 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. </p> <p>The Symbian P.I.P.S. libraries
+are not expected to be dealing with a very large number of file descriptors
+and so <codeph>select()</codeph> should be satisfactory for any applications
+on a phone. </p> <p> <b>Note:</b> P.I.P.S. does not support the <codeph>poll()</codeph> function. </p> <p id="GUID-6B8931EB-7AB9-588C-B419-0CD4BA048397"><b>Monitoring two pipes using
+select()</b> </p> <p>The following code segment shows the usage of the <codeph>select()</codeph> function: </p> <codeblock id="GUID-36B78671-0A09-529C-B167-8F3E10C2CCB5" xml:space="preserve">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(&amp;SelectFDs);
+   FD_SET(ChildProcessFD1, &amp;SelectFDs);
+   MaxFD = ChildProcessFD1;
+   FD_SET(ChildProcessFD2, &amp;SelectFDs);
+   
+   //Calculate the largest Descriptor
+   if (ChildProcessFD2 &gt; 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, &amp;SelectFDs, NULL, NULL, &amp;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, &amp;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, &amp;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;
+}</codeblock> </section>
+<section id="GUID-7582B2CB-AAC8-5E41-ADE1-76C12B691E10"><title>Socket IOCtl
+options</title> <p>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. </p> <p>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 <xref href="GUID-BED8A733-2ED7-31AD-A911-C1F4707C67FD.dita"><apiname>RConnection</apiname></xref> class provides this functionality,
+and is exposed in P.I.P.S. using some extra IOCtl options. </p> <p>The list
+of socket options available in P.I.P.S. are as follows: </p> <table id="GUID-B753C24D-597E-53AB-A633-C128C7316514">
+<tgroup cols="3"><colspec colname="col0"/><colspec colname="col1"/><colspec colname="col2"/>
+<tbody>
+<row>
+<entry><p> <b>Socket Option</b>  </p> </entry>
+<entry><p> <b>New</b>  </p> </entry>
+<entry><p> <b>Description</b>  </p> </entry>
+</row>
+<row>
+<entry><p>SIOCADDRT </p> </entry>
+<entry><p>Yes </p> </entry>
+<entry><p>Adds an entry to the interface routing table using the parameters
+in the <codeph>rtentry</codeph> structure. </p> </entry>
+</row>
+<row>
+<entry><p>SIOCATMARK </p> </entry>
+<entry><p>No </p> </entry>
+<entry><p>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. </p> </entry>
+</row>
+<row>
+<entry><p>SIOCDELRT </p> </entry>
+<entry><p>Yes </p> </entry>
+<entry><p>Deletes an entry from the interface routing table using the parameters
+in the <codeph>rtentry</codeph> structure. </p> </entry>
+</row>
+<row>
+<entry><p>SIOCGIFACTIVECONF </p> </entry>
+<entry><p>Yes </p> </entry>
+<entry><p>Gets a list of interfaces/access points started by P.I.P.S. in an <codeph>ifconf</codeph> structure. </p> </entry>
+</row>
+<row>
+<entry><p>SIOCGIFADDR </p> </entry>
+<entry><p>Yes </p> </entry>
+<entry><p>Gets the interface address. This is valid only for sockets with
+address family AF_INET. </p> </entry>
+</row>
+<row>
+<entry><p>SIOCGIFCONF </p> </entry>
+<entry><p>No </p> </entry>
+<entry><p>Gets a list of available interfaces/access points in an <codeph>ifconf</codeph> structure. </p> </entry>
+</row>
+<row>
+<entry><p>SIOCGIFHWADDR </p> </entry>
+<entry><p>Yes </p> </entry>
+<entry><p>Gets the interface hardware address in an <codeph>ifreq</codeph> structure. </p> </entry>
+</row>
+<row>
+<entry><p>SIOCGIFINDEX </p> </entry>
+<entry><p>Yes </p> </entry>
+<entry><p>Sets the index of an interface/access point from a name in an <codeph>ifreq</codeph> structure. </p> </entry>
+</row>
+<row>
+<entry><p>SIOCGIFNUM </p> </entry>
+<entry><p>Yes </p> </entry>
+<entry><p>Return the total number of IP interfaces configured in the system. </p> </entry>
+</row>
+<row>
+<entry><p>SIOCIFACTIVESTART </p> </entry>
+<entry><p>Yes </p> </entry>
+<entry><p>Attempts to start a sub-connection on an available interface/access
+point using the parameters in an <codeph>ifreq</codeph> structure. </p> </entry>
+</row>
+<row>
+<entry><p>SIOCIFSTART </p> </entry>
+<entry><p>Yes </p> </entry>
+<entry><p>Attempts to start an interface/access point using the parameters
+in an <codeph>ifreq</codeph> structure. </p> </entry>
+</row>
+<row>
+<entry><p>SIOCIFSTOP </p> </entry>
+<entry><p>Yes </p> </entry>
+<entry><p>Stops a previously started interface or sub-connection. </p> </entry>
+</row>
+<row>
+<entry><p>SIOCSIFNAME </p> </entry>
+<entry><p>No </p> </entry>
+<entry><p>Sets the desired interface/access point name to start in an <codeph>ifreq</codeph> structure. </p> </entry>
+</row>
+</tbody>
+</tgroup>
+</table> <p>The follow code for a function shows how to start an interface
+called "3G Access Point" and return the created socket. </p> <codeblock id="GUID-94D8CA06-366E-5697-A72B-891C07F21F8E" xml:space="preserve">int opensocket()
+{
+  int Sock;
+  struct ifreq Ifr;
+  char AccessPoint[]="3G Access Point";
+
+  //Open the socket
+  Sock = socket(AF_INET, SOCK_STREAM, 0);
+  if (Sock &lt; 0) 
+  {
+    printf("\nCannot open socket, error=%d",errno);
+    return -1;
+  }
+
+  //Set up the interface request structure
+  bzero(&amp;Ifr, sizeof(Ifr));
+  strcpy(Ifr.ifr_name, AccessPoint);
+    
+  //Set the requested interface name
+  if (ioctl(Sock, SIOCSIFNAME, &amp;Ifr))
+  {
+    printf("\nCannot set the interface name, error=%d",errno);
+    close(Sock);
+    return -1;
+  }
+
+  //Start the interface
+  if (ioctl(Sock, SIOCIFSTART, &amp;Ifr))
+  {
+    printf("\nCannot start the interface, error=%d",errno);
+    close(Sock);
+    return -1;
+  }
+
+  //Return the opened socket
+  return Sock;
+}</codeblock> </section>
+<section id="GUID-9BF9562E-5831-5A7F-90A1-87BDE1CFBA54"><title>Mathematical
+functions</title> <p>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. </p> <p>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. </p> <p>Symbian platform does not support
+complex numbers so the P.I.P.S. libraries are not able to offer the POSIX
+complex number APIs. </p> <p> <b>Note:</b> The mathematical functions are
+included in the <filepath>libm.dll</filepath> file. </p> </section>
+<section id="GUID-DA65E8FA-E20B-5572-AEC9-20AB140DF33A"><title> Error handling
+and cleanup</title> <p>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 <codeph>errno</codeph> values
+as per the standard. So, ported programs will not usually have to alter their
+error checking/handling. </p> <p id="GUID-D8DB43BD-9D19-5A78-8E37-6699653D047A"><b>Mapping
+P.I.P.S. error codes to Symbian platform error codes</b> </p> <p>Porting your
+application to Symbian platform requires 'translating' Symbian platform error
+codes to POSIX error codes. <xref href="GUID-C197C9A7-EA05-3F24-9854-542E984C612D.dita#GUID-C197C9A7-EA05-3F24-9854-542E984C612D/GUID-B00F7659-9C31-36CD-896A-40887DECEA4B"><apiname>User::Leaves()</apiname></xref> 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 <xref href="GUID-3AD20E0C-F364-533F-9FBC-227478CA9982.dita">TRAP</xref> s. </p> <p>Occasionally
+errors may be generated by the underlying Symbian platform that cannot be
+translated to POSIX error codes, in which case the error variable <codeph>errno</codeph> will
+be out of the usual range of values, above the maximum value of <codeph>__EMAXERRNO</codeph> or <codeph>124</codeph>. </p> <p>The
+Symbian platform error code can be calculated using the following formula: </p> <codeblock id="GUID-A2F7B744-4B73-56AB-BA06-7C83333ADC5D" xml:space="preserve">Symbian Error Code = -(errno - __EMAXERRNO)</codeblock> <p>Error
+codes are defined in the <filepath>errno.h</filepath> file. </p> </section>
+<section id="GUID-CF52A59F-FD04-5043-A526-05545E11F0F5"><title>System logger</title> <p>P.I.P.S.
+does not supply a system logger for use with <xref href="GUID-0138AF2F-50A6-3FAD-8AE9-FDBFD66E5EF5.dita"><apiname>openlog()</apiname></xref>, <xref href="GUID-CCBCF015-F7CF-3A55-A723-0BC4B4DC758C.dita"><apiname>syslog()</apiname></xref> and <xref href="GUID-57C7FF8B-7EB3-35BE-BC9B-5FD6ABEE6225.dita"><apiname>closelog()</apiname></xref>.
+Instead, a rudimentary selection of functions which log to a file can be written
+as demonstrated by the following example. </p> <codeblock id="GUID-EE476405-2657-5827-81F4-DD5A29BF9F35" xml:space="preserve">//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;
+}</codeblock> </section>
+<section id="GUID-8C951D9F-DE32-5201-90F2-45EB442F9FFC"><title>Pthread barriers,
+rwlocks and spinlocks</title> <p>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. </p> <p>The
+following code sample (originally taken from <xref href="http://heather.cs.ucdavis.edu/matloff/public_html/158/PLN/ParProcIntro.pdf" scope="external">http://heather.cs.ucdavis.edu/matloff/public_html/158/PLN/ParProcIntro.pdf</xref>)
+demonstrates an implementation of a simple Pthread barrier. </p> <codeblock id="GUID-A156CD2D-F212-57EA-A23A-C7B7478B431E" xml:space="preserve">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-&gt;nodes = nodes;
+   PB-&gt;count[0] = 0;
+   PB-&gt;count[1] = 0;
+   PB-&gt;whichcount = 0;
+   pthread_mutex_init(&amp;PB-&gt;lock, NULL);
+   pthread_cond_init(&amp;PB-&gt;cv, NULL);
+}
+
+//destroy a barrier
+void DestroyBarrier(struct barrier_t* PB)
+{
+   pthread_mutex_destroy(&amp;PB-&gt;lock);
+   pthread_cond_destroy(&amp;PB-&gt;cv);
+}
+
+//wait for a barrier
+void WaitBarrier(struct barrier_t* PB)
+{
+   int WhichCount, Count;
+   
+   //which counter variable to use
+   WhichCount = PB-&gt;whichcount;
+   
+   //lock the mutex
+   pthread_mutex_lock(&amp;PB-&gt;lock);
+   
+   //get the count of nodes
+   Count = ++PB-&gt;count[WhichCount];
+   
+   //test whether it should block
+   if (Count &lt; PB-&gt;nodes)
+      pthread_cond_wait(&amp;PB-&gt;cv, &amp;PB-&gt;lock);
+   else
+   { 
+      //reset the counter
+      PB-&gt;count[WhichCount] = 0;
+      PB-&gt;whichcount = 1 - WhichCount;
+      
+      //release the wait
+      pthread_cond_broadcast(&amp;PB-&gt;cv);
+   }
+   
+   //unlock the threads
+   pthread_mutex_unlock(&amp;PB-&gt;lock);
+}</codeblock> <p>The following code was posted by Michael M. Lampkin as an
+open source implementation of Pthread spin threads. </p> <codeblock id="GUID-85F81360-113F-54DC-958E-7C76BC8BA98D" xml:space="preserve">/**********************************************************************
+BETA User Space spinlocks for POSIX systems lacking this functionality.
+Copyright ©) 2003-2006 Michael M. Lampkin 
+Contact at michael.lampkin&lt;at&gt;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-&gt;magic )
+  {
+    return EBUSY;
+  }
+
+  ( void ) memset( &amp; spin-&gt;owner, 0, sizeof( pthread_t ) );
+
+  /* Set our process sharing attribute - default to PRIVATE */
+  result = pthread_mutexattr_init( &amp; attr );
+
+  if ( 0 == result )
+  {
+    if ( 0 &lt; sysconf( _SC_THREAD_PROCESS_SHARED ) )
+    {
+      if( PTHREAD_PROCESS_SHARED == pshared )
+      {
+        result = pthread_mutexattr_setpshared( &amp; attr, pshared );
+      }
+      else
+      {
+        result = pthread_mutexattr_setpshared( &amp; attr, PTHREAD_PROCESS_PRIVATE );
+      }
+    }
+  }
+
+  /* Need to add this to prevent recursive mutex default on some sys */
+  if ( 0 == result )
+  {
+    result = pthread_mutexattr_settype( &amp; attr, PTHREAD_MUTEX_ERRORCHECK );
+  }
+
+  /* The following is a race against simultaneous calls to init */
+  if ( 0 == result )
+  {
+    result = pthread_mutex_init( &amp; spin-&gt;mutex, &amp; attr );
+  }
+
+  if ( 0 == result )
+  {
+    spin-&gt;magic = spin_magic;     
+  }
+
+  ( void ) pthread_mutexattr_destroy( &amp; 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-&gt;magic )
+  {
+    return EINVAL;
+  }
+
+  if ( 0 != ( result = pthread_mutex_destroy( &amp; spin-&gt;mutex ) ) )
+  {
+    return result;
+  }
+
+  ( void ) memset( &amp; spin-&gt;owner, 0, sizeof( pthread_t ) );
+
+  /**
+   A return of EINVAL on destroy means another thread is
+   also destroying.  Ignore it.
+  **/
+  spin-&gt;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-&gt;magic )
+  {
+    return EINVAL;
+  }
+
+  self = pthread_self( );
+  if ( 0 == memcmp( &amp; spin-&gt;owner, &amp; self, sizeof( pthread_t ) ) )
+  {
+    return EDEADLK;
+  }
+
+  for ( ; 0 != ( result = pthread_mutex_trylock( &amp; spin-&gt;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( &amp; spin-&gt;owner, &amp; self, sizeof( pthread_t ) );
+  return result;
+}
+
+/**</codeblock> </section>
+<section id="GUID-777FDBF9-4B80-5B58-88F3-E78DBDB89021"><title>Command line
+shell</title> <p>Symbian platform phones do not have a command line shell
+as standard. P.I.P.S. does however support the <xref href="GUID-C0C1D22B-298F-3E8D-A1E9-6F5EFA81F9E8.dita"><apiname>stdin()</apiname></xref>, <xref href="GUID-85797574-E2A2-3C0C-9670-C178078DE199.dita"><apiname>stdout()</apiname></xref> and <xref href="GUID-4FF97B50-2C1E-37EC-888B-FB8D3F14B5B8.dita"><apiname>stderr()</apiname></xref> 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 <filepath>/dev/null</filepath> directory.
+The P.I.P.S. <xref href="GUID-3D9040E5-F6FB-3DEA-9800-A55F0CEE7B08.dita"><apiname>system()</apiname></xref> 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. </p> </section>
+<section id="GUID-98FE0A61-A9F6-5216-A01F-A213F33D3173"><title>User interfaces</title> <p>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. </p> </section>
+<section id="GUID-3CA8FF29-79B4-5D43-8A23-EDB136BF7A8F"><title>One Definition
+Rule - warning</title> <p>Standard C++ states that the <keyword>One Definition
+Rule</keyword> (ODR) must be maintained within a program. </p> <p>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. </p> <p>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. </p> </section>
+</conbody></concept>
\ No newline at end of file