Symbian3/SDK/Source/GUID-6590B534-D976-5305-BE95-48DD05120DFB.dita
author Dominic Pinkman <dominic.pinkman@nokia.com>
Tue, 20 Jul 2010 12:00:49 +0100
changeset 13 48780e181b38
parent 7 51a74ef9ed63
permissions -rw-r--r--
Week 28 contribution of SDK documentation content. See release notes for details. Fixes bugs Bug 1897 and Bug 1522.

<?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 the 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 the 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>The 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>The 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>The 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 the 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 the Symbian platform error codes</b> </p> <p>Porting
your application to the Symbian platform requires 'translating' the 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>The 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 the 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>The 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>