--- a/Symbian3/PDK/Source/GUID-6590B534-D976-5305-BE95-48DD05120DFB.dita Tue Jul 20 12:00:49 2010 +0100
+++ b/Symbian3/PDK/Source/GUID-6590B534-D976-5305-BE95-48DD05120DFB.dita Fri Aug 13 16:47:46 2010 +0100
@@ -1,679 +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 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(&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;
-}</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 < 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;
-}</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->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);
-}</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<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;
-}
-
-/**</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>
+<?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(&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;
+}</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 < 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;
+}</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->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);
+}</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<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;
+}
+
+/**</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>
\ No newline at end of file