Adaptation/GUID-51514A4B-0220-557B-9F7A-FB110CEFEF10.dita
changeset 15 307f4279f433
equal deleted inserted replaced
14:578be2adaf3e 15:307f4279f433
       
     1 <?xml version="1.0" encoding="utf-8"?>
       
     2 <!-- Copyright (c) 2007-2010 Nokia Corporation and/or its subsidiary(-ies) All rights reserved. -->
       
     3 <!-- This component and the accompanying materials are made available under the terms of the License 
       
     4 "Eclipse Public License v1.0" which accompanies this distribution, 
       
     5 and is available at the URL "http://www.eclipse.org/legal/epl-v10.html". -->
       
     6 <!-- Initial Contributors:
       
     7     Nokia Corporation - initial contribution.
       
     8 Contributors: 
       
     9 -->
       
    10 <!DOCTYPE concept
       
    11   PUBLIC "-//OASIS//DTD DITA Concept//EN" "concept.dtd">
       
    12 <concept id="GUID-51514A4B-0220-557B-9F7A-FB110CEFEF10" xml:lang="en"><title>Shared
       
    13 Chunks</title><shortdesc>A shared chunk is a mechanism that kernel-side code uses to share
       
    14 memory buffers safely with user-side code. </shortdesc><prolog><metadata><keywords/></metadata></prolog><conbody>
       
    15 <p>A shared chunk is a mechanism that kernel-side code can use to share memory
       
    16 buffers safely with user-side code. This topic describes this concept, and
       
    17 explains how to use the shared chunk APIs. </p>
       
    18 <ul>
       
    19 <li id="GUID-2D439828-C4DB-5D0F-83EF-46EDD9D2C2CF"><p> <xref href="GUID-51514A4B-0220-557B-9F7A-FB110CEFEF10.dita#GUID-51514A4B-0220-557B-9F7A-FB110CEFEF10/GUID-F09BAE7B-805F-5CF1-8C9A-AD23C50026AD">What are shared chunks?</xref>  </p> </li>
       
    20 <li id="GUID-EE669369-2315-5EB3-A4EF-CF1778DF4432"><p> <xref href="GUID-51514A4B-0220-557B-9F7A-FB110CEFEF10.dita#GUID-51514A4B-0220-557B-9F7A-FB110CEFEF10/GUID-FBFA1B23-C6CA-5E9A-A461-E4822EB9E76F">Creating a shared chunk</xref>  </p> </li>
       
    21 <li id="GUID-0BE8F408-05E8-5F1A-987A-E35CD8D92703"><p> <xref href="GUID-51514A4B-0220-557B-9F7A-FB110CEFEF10.dita#GUID-51514A4B-0220-557B-9F7A-FB110CEFEF10/GUID-D55514EA-D218-52F2-807B-78D58E99D810">Opening a handle to the shared chunk for user-side access</xref>  </p> </li>
       
    22 <li id="GUID-5A0B2A6A-169F-5158-B554-A346C34C16D7"><p> <xref href="GUID-51514A4B-0220-557B-9F7A-FB110CEFEF10.dita#GUID-51514A4B-0220-557B-9F7A-FB110CEFEF10/GUID-F63A506B-1573-5F6A-B0C7-CEE5BF1FAD72">Discarding a handle</xref>  </p> </li>
       
    23 <li id="GUID-9ED0C21B-5B51-5E38-B77F-96E879E9A053"><p> <xref href="GUID-51514A4B-0220-557B-9F7A-FB110CEFEF10.dita#GUID-51514A4B-0220-557B-9F7A-FB110CEFEF10/GUID-86446948-6012-59B9-8411-BF0E98DC7D3A">Closing and destroying a shared chunk</xref>  </p> </li>
       
    24 <li id="GUID-9E297A46-9C63-59C2-A515-1AB8F3BD09BA"><p> <xref href="GUID-51514A4B-0220-557B-9F7A-FB110CEFEF10.dita#GUID-51514A4B-0220-557B-9F7A-FB110CEFEF10/GUID-6D3AAC95-E52B-5E78-B57E-0433ECF14C3A">Committing memory</xref>  </p> </li>
       
    25 <li id="GUID-BF5A0349-1DD7-5266-9F86-1DC3F73CC2CC"><p> <xref href="GUID-51514A4B-0220-557B-9F7A-FB110CEFEF10.dita#GUID-51514A4B-0220-557B-9F7A-FB110CEFEF10/GUID-E9630D2D-794B-5AB1-8980-0927E040C0C5">Passing data from user-side code to another device driver</xref>  </p> </li>
       
    26 <li id="GUID-EA0A1F4A-DB1D-55F8-8EB1-C3E139AA9B47"><p> <xref href="GUID-51514A4B-0220-557B-9F7A-FB110CEFEF10.dita#GUID-51514A4B-0220-557B-9F7A-FB110CEFEF10/GUID-4C374CF0-0680-5A27-94E7-BB0FD75413AF">Passing data between user-side code</xref>  </p> </li>
       
    27 <li id="GUID-A0448628-461A-52F9-A2D4-DE3863005966"><p> <xref href="GUID-51514A4B-0220-557B-9F7A-FB110CEFEF10.dita#GUID-51514A4B-0220-557B-9F7A-FB110CEFEF10/GUID-A8FF0519-9FDC-53D5-8BD6-A3AEA6BFDD46">Direct peripheral access to shared chunks</xref>  </p> </li>
       
    28 <li id="GUID-C6A46B05-12C8-5459-ABD7-0BD173E36580"><p> <xref href="GUID-51514A4B-0220-557B-9F7A-FB110CEFEF10.dita#GUID-51514A4B-0220-557B-9F7A-FB110CEFEF10/GUID-D8E298EA-A4CD-5501-B5F1-B8F0EE93CE84"> Example code</xref>  </p> <ul>
       
    29 <li id="GUID-B17ECEF5-920C-516C-80D1-15AFD3FAA282"><p> <xref href="GUID-51514A4B-0220-557B-9F7A-FB110CEFEF10.dita#GUID-51514A4B-0220-557B-9F7A-FB110CEFEF10/GUID-D284D6D0-400D-53D2-9A43-05CEE28DFDC4">Example: Creating a shared chunk</xref>  </p> </li>
       
    30 <li id="GUID-75FB5604-6468-502B-A005-38D81DE03588"><p> <xref href="GUID-51514A4B-0220-557B-9F7A-FB110CEFEF10.dita#GUID-51514A4B-0220-557B-9F7A-FB110CEFEF10/GUID-6501F90A-5330-5BC9-A991-A3BECCCA6CDD">Example: Opening a handle to the shared chunk for user-side access</xref>  </p> </li>
       
    31 <li id="GUID-FF092178-84C4-5996-85C2-6B9E111EFFD6"><p> <xref href="GUID-51514A4B-0220-557B-9F7A-FB110CEFEF10.dita#GUID-51514A4B-0220-557B-9F7A-FB110CEFEF10/GUID-062C405B-B10F-54A8-8F61-418CAE6019D8">Example: Using a DFC to notify destruction of chunk</xref>  </p> </li>
       
    32 <li id="GUID-02D42EFC-B20B-5E34-B555-657DC5DFB748"><p> <xref href="GUID-51514A4B-0220-557B-9F7A-FB110CEFEF10.dita#GUID-51514A4B-0220-557B-9F7A-FB110CEFEF10/GUID-97BF15A2-E74A-51DE-B003-16E1DFF8964E">Example: Committing memory</xref>  </p> </li>
       
    33 </ul> </li>
       
    34 </ul>
       
    35 <p>You may find it useful to refer to the general sections : <xref href="GUID-8D80AA51-5108-5D4B-B6B9-7FA47570AB89.dita">Device
       
    36 Driver Concepts</xref> and <xref href="GUID-4A402DAD-99D3-595E-87FD-AAB5A970D6CC.dita">Device
       
    37 Driver Framework</xref>. </p>
       
    38 <section id="GUID-F09BAE7B-805F-5CF1-8C9A-AD23C50026AD"><title>What are shared
       
    39 chunks?</title> <p>A shared chunk is a mechanism that kernel-side code uses
       
    40 to share memory buffers safely with user-side code. References to kernel-side
       
    41 code always mean device driver code. </p> <p>The main points to note about
       
    42 shared chunks are: </p> <ul>
       
    43 <li id="GUID-9B4BC2DE-59AD-50F9-AF37-4966D741741A"><p>They can be created
       
    44 and destroyed only by device drivers. It is typical behaviour for user-side
       
    45 code, which in this context we refer to as the <i>client</i> of the device
       
    46 driver, to pass a request to the device driver for a handle to a shared chunk.
       
    47 This causes the device driver to open a handle to the chunk and return the
       
    48 handle <i>value</i> to the client. Successful handle creation also causes
       
    49 the chunk's memory to be mapped into the address space of the process to which
       
    50 the client's thread belongs. Note, however, that the driver dictates <i>when</i> the
       
    51 chunk needs to be created, and <i>when</i> memory needs to be committed. </p> </li>
       
    52 <li id="GUID-B5D39B0E-150A-56E8-A396-EDDC36D3061B"><p>Like all kernel-side
       
    53 objects, a shared chunk is reference counted. This means that it remains in
       
    54 existence for as long as the reference count is greater than zero. Once all
       
    55 opened references to the shared chunk have been <i>closed</i>, regardless
       
    56 of whether the references are user-side or kernel-side, it is destroyed. </p> </li>
       
    57 <li id="GUID-348564CB-647F-5658-9DDC-5E0B022B7644"><p>User-side code that
       
    58 has gained access to a shared chunk from one device driver can pass this to
       
    59 a second device driver. The second device driver must <i>open</i> the chunk
       
    60 before it can be used. </p> </li>
       
    61 <li id="GUID-8496E32C-48C7-5778-B886-0F63C6EF7ED6"><p>More than one user-side
       
    62 application can access the data in a shared chunk. A handle to a shared chunk
       
    63 can be passed from one process to another using standard handle passing mechanisms.
       
    64 In practice, handles are almost always passed in a client-server context via
       
    65 inter process communication (IPC). </p> </li>
       
    66 <li id="GUID-8F0AAFD5-661A-5569-AABF-C88287DF836B"><p>Processes that share
       
    67 the data inside a chunk should communicate the location of that data as an
       
    68 offset from the start of the chunk, and <i>not</i> as an absolute address.
       
    69 The shared chunk may appear at different addresses in the address spaces of
       
    70 different user processes. </p> </li>
       
    71 </ul> </section>
       
    72 <section id="GUID-FBFA1B23-C6CA-5E9A-A461-E4822EB9E76F"><title>Creating a
       
    73 shared chunk</title> <p>A shared chunk can be created only by code running
       
    74 on the kernel-side. This means that it is the device driver's responsibility
       
    75 to create a chunk that is to be shared by user-side code. There is <i>no user-side
       
    76 API</i> that allows user-side code to create shared chunks. </p> <p>The device
       
    77 driver creates a shared chunk using the <xref href="GUID-C6946ECB-775F-3EC2-A56F-78F25B9FBE3D.dita#GUID-C6946ECB-775F-3EC2-A56F-78F25B9FBE3D/GUID-F8D1FB29-7238-3438-951A-6F853C7CF817"><apiname>Kern::ChunkCreate()</apiname></xref> function.
       
    78 It passes to this function a <xref href="GUID-51F7DBCF-BFB6-31F9-8882-5D263A1AD4B4.dita"><apiname>TChunkCreateInfo</apiname></xref> object containing
       
    79 the required attributes for that chunk. The most important attribute is the <xref href="GUID-51F7DBCF-BFB6-31F9-8882-5D263A1AD4B4.dita#GUID-51F7DBCF-BFB6-31F9-8882-5D263A1AD4B4/GUID-B00A3693-50B6-3A84-89E0-B06D9ABE82ED"><apiname>TChunkCreateInfo::ESharedKernelMultiple</apiname></xref> attribute
       
    80 that states that a shared chunk is to be created. </p> <p>Chunks are reference
       
    81 counted kernel objects. When the chunk is created, the reference count is
       
    82 set to one. </p> <p>See <xref href="GUID-51514A4B-0220-557B-9F7A-FB110CEFEF10.dita#GUID-51514A4B-0220-557B-9F7A-FB110CEFEF10/GUID-D284D6D0-400D-53D2-9A43-05CEE28DFDC4">Example:
       
    83 Creating a shared chunk</xref>. </p> </section>
       
    84 <section id="GUID-D55514EA-D218-52F2-807B-78D58E99D810"><title>Opening a handle
       
    85 to the shared chunk for user-side access</title> <p>Before user-side code
       
    86 can access the memory in a shared chunk, the device driver must create a handle
       
    87 to the chunk and then pass the value back to the user-side. It does this by
       
    88 calling the <xref href="GUID-C6946ECB-775F-3EC2-A56F-78F25B9FBE3D.dita#GUID-C6946ECB-775F-3EC2-A56F-78F25B9FBE3D/GUID-BA56B205-60D8-326E-8340-3F78CCEA3DD1"><apiname>Kern::MakeHandleAndOpen()</apiname></xref> function, passing
       
    89 the information: </p> <ul>
       
    90 <li id="GUID-178CFDE6-BBB0-5A37-A680-13F4E0463248"><p>a pointer to the user-side
       
    91 code's thread (or NULL if referring to the current thread) </p> </li>
       
    92 <li id="GUID-7A39F8FA-B7E8-5E27-BA07-D1CA6179B8BF"><p>a pointer to the shared
       
    93 chunk </p> </li>
       
    94 </ul> <p>Typically, the device driver does this in response to a request from
       
    95 the user-side. <xref href="GUID-C6946ECB-775F-3EC2-A56F-78F25B9FBE3D.dita#GUID-C6946ECB-775F-3EC2-A56F-78F25B9FBE3D/GUID-BA56B205-60D8-326E-8340-3F78CCEA3DD1"><apiname>Kern::MakeHandleAndOpen()</apiname></xref> also maps the
       
    96 chunk's memory into the address space of the user-side code's thread. </p> <p>If
       
    97 the creation of the handle is successful, the device driver returns the handle <i>value</i> back
       
    98 to the user-side. The user-side code then assigns the value to an <xref href="GUID-326A2F4D-0E99-31C0-A35D-E8BF45913F07.dita"><apiname>RChunk</apiname></xref> object
       
    99 using one of <codeph>RChunk</codeph>'s base class functions: </p> <ul>
       
   100 <li id="GUID-091419E2-3BA4-5821-8138-A1047A6070BF"><p> <xref href="GUID-727D2B62-09A9-3CBC-AB6F-591E52EC68EB.dita#GUID-727D2B62-09A9-3CBC-AB6F-591E52EC68EB/GUID-C7E88CD7-A32B-3585-9D8B-3A0726947690"><apiname>RHandleBase::SetHandle()</apiname></xref>  </p> </li>
       
   101 <li id="GUID-7974DC49-8CDA-5660-9C8D-709D1FDCA478"><p> <xref href="GUID-727D2B62-09A9-3CBC-AB6F-591E52EC68EB.dita#GUID-727D2B62-09A9-3CBC-AB6F-591E52EC68EB/GUID-9AEAD2B5-4531-3157-839C-CBAECBFCF069"><apiname>RHandleBase::SetReturnedHandle()</apiname></xref>  </p> </li>
       
   102 </ul> <p>The user-side code uses <xref href="GUID-727D2B62-09A9-3CBC-AB6F-591E52EC68EB.dita#GUID-727D2B62-09A9-3CBC-AB6F-591E52EC68EB/GUID-9AEAD2B5-4531-3157-839C-CBAECBFCF069"><apiname>RHandleBase::SetReturnedHandle()</apiname></xref> if
       
   103 the device driver returns either a positive handle value or a negative error
       
   104 code. A negative error code means that handle creation has failed. </p> <p>Opening
       
   105 a handle to a shared chunk increases the reference count by one. </p> <p>See <xref href="GUID-51514A4B-0220-557B-9F7A-FB110CEFEF10.dita#GUID-51514A4B-0220-557B-9F7A-FB110CEFEF10/GUID-6501F90A-5330-5BC9-A991-A3BECCCA6CDD">Example:
       
   106 Opening a handle to the shared chunk for user-side access</xref>. </p> </section>
       
   107 <section id="GUID-F63A506B-1573-5F6A-B0C7-CEE5BF1FAD72"><title>Closing a handle</title> <p>After
       
   108 it has been opened, a device driver may need to perform further operations
       
   109 before the handle can be returned to the user-side. If these operations fail,
       
   110 the device driver code may want to unwind the processing it has done, including
       
   111 discarding the handle it has just created. It does this using the function <xref href="GUID-C6946ECB-775F-3EC2-A56F-78F25B9FBE3D.dita#GUID-C6946ECB-775F-3EC2-A56F-78F25B9FBE3D/GUID-71A20F01-5E5F-3B27-92BA-3B3BF7D578C9"><apiname>Kern::CloseHandle()</apiname></xref>. </p> <p>This
       
   112 reverses the operation performed by <xref href="GUID-C6946ECB-775F-3EC2-A56F-78F25B9FBE3D.dita#GUID-C6946ECB-775F-3EC2-A56F-78F25B9FBE3D/GUID-BA56B205-60D8-326E-8340-3F78CCEA3DD1"><apiname>Kern::MakeHandleAndOpen()</apiname></xref>. </p> </section>
       
   113 <section id="GUID-86446948-6012-59B9-8411-BF0E98DC7D3A"><title>Closing and
       
   114 destroying a shared chunk</title> <p>There is no explicit method for deleting
       
   115 or destroying shared chunks. Instead, because chunks are reference counted
       
   116 kernel objects, a device driver can use the function <xref href="GUID-C6946ECB-775F-3EC2-A56F-78F25B9FBE3D.dita#GUID-C6946ECB-775F-3EC2-A56F-78F25B9FBE3D/GUID-480F655A-5B93-3E8A-8964-3A04682C3CCF"><apiname>Kern::ChunkClose()</apiname></xref>.
       
   117 This function decrements a chunk's access count, and, if the count reaches
       
   118 zero, the chunk is scheduled for destruction. </p> <p>The chunk is not be
       
   119 destroyed immediately. Instead it is done asynchronously. If the device driver
       
   120 needs to know when the chunk has been destroyed, it must specify a DFC (Deferred
       
   121 Function Call) at the time the chunk is created. The device driver specifies
       
   122 the DFC through the <xref href="GUID-51F7DBCF-BFB6-31F9-8882-5D263A1AD4B4.dita#GUID-51F7DBCF-BFB6-31F9-8882-5D263A1AD4B4/GUID-58271733-146A-3ECB-91AC-C38BD2ADC9A0"><apiname>TChunkCreateInfo::iDestroyedDfc</apiname></xref> member.
       
   123 The DFC is queued to run only when the chunk has finally been destroyed. At
       
   124 this point it is guaranteed that the memory mapped by the chunk can no longer
       
   125 be accessed by any code. This is useful in cases where chunks are used to
       
   126 map I/O devices or other special memory, and the program managing these needs
       
   127 to know when they are free to be reused. </p> <p> <b> Note:</b> For each call
       
   128 to <xref href="GUID-C6946ECB-775F-3EC2-A56F-78F25B9FBE3D.dita#GUID-C6946ECB-775F-3EC2-A56F-78F25B9FBE3D/GUID-F8D1FB29-7238-3438-951A-6F853C7CF817"><apiname>Kern::ChunkCreate()</apiname></xref> and <xref href="GUID-C6946ECB-775F-3EC2-A56F-78F25B9FBE3D.dita#GUID-C6946ECB-775F-3EC2-A56F-78F25B9FBE3D/GUID-DAEE47C8-40ED-3F95-9EE9-29033FC5A8D3"><apiname>Kern::OpenSharedChunk()</apiname></xref> there
       
   129 should be <i>exactly one</i> call to <xref href="GUID-C6946ECB-775F-3EC2-A56F-78F25B9FBE3D.dita#GUID-C6946ECB-775F-3EC2-A56F-78F25B9FBE3D/GUID-480F655A-5B93-3E8A-8964-3A04682C3CCF"><apiname>Kern::ChunkClose()</apiname></xref>.
       
   130 Calling <codeph>Close()</codeph> too few times can cause memory leaks. Calling <codeph>Close()</codeph> too
       
   131 many times can cause the chunk to be destroyed while a program is still trying
       
   132 to access the memory, which causes an application panic for user code and
       
   133 a system crash for kernel code. </p> </section>
       
   134 <section id="GUID-6D3AAC95-E52B-5E78-B57E-0433ECF14C3A"><title>Committing
       
   135 memory</title> <p>After a shared chunk has been created it owns a region of
       
   136 contiguous virtual addresses. This region is empty, which means that it is
       
   137 not mapped to any physical RAM or memory mapped I/O devices. </p> <p>Before
       
   138 the chunk can be used, the virtual memory must be mapped to real physical
       
   139 memory. This is known as <i>committing</i> memory. </p> <p><b>Committing RAM
       
   140 from the system free memory pool</b> </p> <p>You can commit RAM taken from
       
   141 the system free memory pool using the following ways: </p> <ul>
       
   142 <li id="GUID-7E755F49-D5E6-538C-9CE1-947310DD94A7"><p>by committing an arbitrary
       
   143 set of pages. Use the function <xref href="GUID-C6946ECB-775F-3EC2-A56F-78F25B9FBE3D.dita#GUID-C6946ECB-775F-3EC2-A56F-78F25B9FBE3D/GUID-9FCD7C2A-5192-3B99-8ACF-2802C1A3FAA1"><apiname>Kern::ChunkCommit()</apiname></xref>. </p> </li>
       
   144 <li id="GUID-738B8FF3-5848-54F9-B872-179317BE9B4B"><p>by committing a set
       
   145 of pages with physically contiguous addresses. Use the function <xref href="GUID-C6946ECB-775F-3EC2-A56F-78F25B9FBE3D.dita#GUID-C6946ECB-775F-3EC2-A56F-78F25B9FBE3D/GUID-E1B88A30-6572-3E0B-B6BB-ED4359D7A5FD"><apiname>Kern::ChunkCommitContiguous()</apiname></xref>. </p> </li>
       
   146 </ul> <p><b>Committing specified physical addresses</b> </p> <p>You can commit
       
   147 specific physical addresses, but only if you set the data member <xref href="GUID-51F7DBCF-BFB6-31F9-8882-5D263A1AD4B4.dita#GUID-51F7DBCF-BFB6-31F9-8882-5D263A1AD4B4/GUID-106850A0-5498-387F-AF70-F9D04EB6318D"><apiname>TChunkCreateInfo::iOwnsMemory</apiname></xref> to <xref href="GUID-A759CA2D-8327-348F-9337-4886E619D920.dita"><apiname>EFalse</apiname></xref> when
       
   148 you create the shared chunk - see <xref href="GUID-51514A4B-0220-557B-9F7A-FB110CEFEF10.dita#GUID-51514A4B-0220-557B-9F7A-FB110CEFEF10/GUID-FBFA1B23-C6CA-5E9A-A461-E4822EB9E76F">Creating
       
   149 a shared chunk</xref>. </p> <p>You can use the following ways to do this: </p> <ul>
       
   150 <li id="GUID-2DCE4AB8-A5CF-536C-8FC1-414755AAC894"><p>by committing a region
       
   151 of contiguous addresses. Use the function <xref href="GUID-C6946ECB-775F-3EC2-A56F-78F25B9FBE3D.dita#GUID-C6946ECB-775F-3EC2-A56F-78F25B9FBE3D/GUID-F3A3D9F5-5885-38B2-9711-1DF99C36F62D"><apiname>Kern::ChunkCommitPhysical()</apiname></xref> with
       
   152 the signature: </p> <codeblock id="GUID-E159781F-7B60-5A2B-A8EE-3BB6B9CEADBB" xml:space="preserve">TInt Kern::ChunkCommitPhysical(DChunk*, TInt, TInt, TUint32)</codeblock> </li>
       
   153 <li id="GUID-5CC4AB75-BF24-5C86-B87B-CA4CDFF6ED5E"><p>by committing an arbitrary
       
   154 set of physical pages. Use the function <xref href="GUID-C6946ECB-775F-3EC2-A56F-78F25B9FBE3D.dita#GUID-C6946ECB-775F-3EC2-A56F-78F25B9FBE3D/GUID-F3A3D9F5-5885-38B2-9711-1DF99C36F62D"><apiname>Kern::ChunkCommitPhysical()</apiname></xref> with
       
   155 the signature: </p> <codeblock id="GUID-321BD1CC-95D4-5539-9C24-187944AA9D90" xml:space="preserve">TInt Kern::ChunkCommitPhysical(DChunk*, TInt, TInt, const TUint32*)</codeblock> </li>
       
   156 </ul> <p>Note: the same physical memory can be committed to two different <xref href="GUID-326A2F4D-0E99-31C0-A35D-E8BF45913F07.dita"><apiname>RChunk</apiname></xref> s
       
   157 or shared chunks at the same time, where each <xref href="GUID-326A2F4D-0E99-31C0-A35D-E8BF45913F07.dita"><apiname>RChunk</apiname></xref> has
       
   158 a different owner, as long as your turn OFF the caches. </p> </section>
       
   159 <section id="GUID-E9630D2D-794B-5AB1-8980-0927E040C0C5"><title>Passing data
       
   160 from user-side code to another device driver</title> <p>User-side code that
       
   161 has access to a shared chunk from one device driver may want to use this when
       
   162 it communicates with another device driver. To enable this, the second device
       
   163 driver needs to gain access to the chunk and the addresses used by the memory
       
   164 it represents. </p> <p>The second driver must open a handle on the shared
       
   165 chunk before any of its code can safely access the memory represented by that
       
   166 chunk. Once it has done this, the reference counted nature of chunks means
       
   167 that the chunk, and the memory it represents, remains accessible until the
       
   168 chunk is closed. </p> <p>The general pattern is: </p> <ul>
       
   169 <li id="GUID-03CA36B3-E327-5632-BAC4-80386B6EADC5"><p>the first device driver
       
   170 creates the shared chunk. </p> <p>See <xref href="GUID-51514A4B-0220-557B-9F7A-FB110CEFEF10.dita#GUID-51514A4B-0220-557B-9F7A-FB110CEFEF10/GUID-FBFA1B23-C6CA-5E9A-A461-E4822EB9E76F">Creating
       
   171 a shared chunk</xref>. </p> </li>
       
   172 <li id="GUID-510CA2F2-B9D5-5342-8739-566EBC0BAAC9"><p>the user-side gets the
       
   173 handle <i>value</i> from the first device driver and calls <codeph>SetHandle()</codeph> or <codeph>SetReturnedHandle()</codeph> on
       
   174 an <xref href="GUID-326A2F4D-0E99-31C0-A35D-E8BF45913F07.dita"><apiname>RChunk</apiname></xref> object [the functions are members of <codeph>RChunk</codeph>'s
       
   175 base class <xref href="GUID-727D2B62-09A9-3CBC-AB6F-591E52EC68EB.dita"><apiname>RHandleBase</apiname></xref> (see <xref href="GUID-727D2B62-09A9-3CBC-AB6F-591E52EC68EB.dita#GUID-727D2B62-09A9-3CBC-AB6F-591E52EC68EB/GUID-C7E88CD7-A32B-3585-9D8B-3A0726947690"><apiname>RHandleBase::SetHandle()</apiname></xref> and <xref href="GUID-727D2B62-09A9-3CBC-AB6F-591E52EC68EB.dita#GUID-727D2B62-09A9-3CBC-AB6F-591E52EC68EB/GUID-9AEAD2B5-4531-3157-839C-CBAECBFCF069"><apiname>RHandleBase::SetReturnedHandle()</apiname></xref>]. </p> <p>See <xref href="GUID-51514A4B-0220-557B-9F7A-FB110CEFEF10.dita#GUID-51514A4B-0220-557B-9F7A-FB110CEFEF10/GUID-D55514EA-D218-52F2-807B-78D58E99D810">Opening
       
   176 a handle to the shared chunk for user-side access</xref>. </p> </li>
       
   177 <li id="GUID-3FFCE699-19F1-5A35-BEE6-96FB706EC16F"><p>the user-side passes
       
   178 the handle <i>value</i> to the second device driver. This value is obtained
       
   179 by calling <codeph>Handle()</codeph> on the <xref href="GUID-326A2F4D-0E99-31C0-A35D-E8BF45913F07.dita"><apiname>RChunk</apiname></xref> object.
       
   180 [the function is a member of <codeph>RChunk</codeph>'s base class <xref href="GUID-727D2B62-09A9-3CBC-AB6F-591E52EC68EB.dita"><apiname>RHandleBase</apiname></xref> (see <xref href="GUID-727D2B62-09A9-3CBC-AB6F-591E52EC68EB.dita#GUID-727D2B62-09A9-3CBC-AB6F-591E52EC68EB/GUID-5B4C908D-AA34-3F1A-8170-77C4C1F829F0"><apiname>RHandleBase::Handle()</apiname></xref>]. </p> </li>
       
   181 <li id="GUID-8337612F-E476-52BC-8A4F-39099DD0F351"><p>the second device driver
       
   182 calls the variant of <xref href="GUID-C6946ECB-775F-3EC2-A56F-78F25B9FBE3D.dita#GUID-C6946ECB-775F-3EC2-A56F-78F25B9FBE3D/GUID-DAEE47C8-40ED-3F95-9EE9-29033FC5A8D3"><apiname>Kern::OpenSharedChunk()</apiname></xref> with the signature: </p> <codeblock id="GUID-9B2095EE-14E9-5E05-8CD4-67DCB62E3583" xml:space="preserve">DChunk* Kern::OpenSharedChunk(DThread*,TInt,TBool)</codeblock> <p>to
       
   183 open a handle to the shared chunk. </p> <p> <b> Note:</b> there are situations
       
   184 where the second device driver cannot use this variant of <codeph>Kern::OpenSharedChunk()</codeph> because: </p> <ul>
       
   185 <li id="GUID-FDAE7AC0-17AF-5EF8-BEE1-9B58A97B4283"><p>The user-side application
       
   186 may have obtained data by using a library API that uses shared chunks internally,
       
   187 but which only presents a descriptor based API to the user application. For
       
   188 example, an image conversion library may perform JPEG decoding using a DSP,
       
   189 which puts its output into a shared chunk, but that library supplies the user
       
   190 application with only a descriptor for the decoded data, not a chunk handle. </p> </li>
       
   191 <li id="GUID-45844589-86D5-5FB8-AEA7-D5586DA45E87"><p>The communication channel
       
   192 between the user-side application and the device driver supports descriptor
       
   193 based APIs only, and does not have an API specifically for shared chunks.
       
   194 The API items presented by the File Server are an example of this situation. </p> </li>
       
   195 </ul> <p>The second device driver will only have the address and size of the
       
   196 data (usually a descriptor). If the driver needs to optimise the case where
       
   197 it knows that this data resides in a shared chunk, it can use the variant
       
   198 of <xref href="GUID-C6946ECB-775F-3EC2-A56F-78F25B9FBE3D.dita#GUID-C6946ECB-775F-3EC2-A56F-78F25B9FBE3D/GUID-DAEE47C8-40ED-3F95-9EE9-29033FC5A8D3"><apiname>Kern::OpenSharedChunk()</apiname></xref> with the signature: </p> <codeblock id="GUID-8CCA35C1-ABBE-5C9D-ABB9-0233E074A14F" xml:space="preserve">DChunk* Kern::OpenSharedChunk(DThread*,const TAny*,TBool,TInt&amp;)</codeblock> <p>to
       
   199 speculatively open the chunk. </p> </li>
       
   200 </ul> <p><b>Getting the virtual address of data in a shared chunk </b> </p> <p>Before
       
   201 device driver code can access a shared chunk that is has opened, it must get
       
   202 the address of the data within it. Typically, user-side code will pass offset
       
   203 and size values to the driver. The driver converts this information into an
       
   204 address, using the function <xref href="GUID-C6946ECB-775F-3EC2-A56F-78F25B9FBE3D.dita#GUID-C6946ECB-775F-3EC2-A56F-78F25B9FBE3D/GUID-626CCD99-63D8-322A-A807-9DB96523C82D"><apiname>Kern::ChunkAddress()</apiname></xref>. </p> <p><b>Getting
       
   205 the physical address of data in a shared chunk </b> </p> <p>Device driver
       
   206 code can get the physical address of a region within a shared chunk from the
       
   207 offset into the chunk and a size value. This is useful for DMA or any other
       
   208 task that needs a physical address. Use the function <xref href="GUID-C6946ECB-775F-3EC2-A56F-78F25B9FBE3D.dita#GUID-C6946ECB-775F-3EC2-A56F-78F25B9FBE3D/GUID-79F110C1-2764-34B5-857B-6C0012D2049D"><apiname>Kern::ChunkPhysicalAddress()</apiname></xref> to
       
   209 do this. </p> <p><b>Getting chunk attributes and checking for uncommitted
       
   210 memory </b> </p> <p>As a shared chunk may contain uncommitted regions of memory
       
   211 (gaps), it is important that these gaps are detected. Any attempt to access
       
   212 a bad address causes an exception. You can use the function <xref href="GUID-C6946ECB-775F-3EC2-A56F-78F25B9FBE3D.dita#GUID-C6946ECB-775F-3EC2-A56F-78F25B9FBE3D/GUID-79F110C1-2764-34B5-857B-6C0012D2049D"><apiname>Kern::ChunkPhysicalAddress()</apiname></xref> to
       
   213 check for uncommitted regions of memory. </p> </section>
       
   214 <section id="GUID-4C374CF0-0680-5A27-94E7-BB0FD75413AF"><title>Passing data
       
   215 between user-side code</title> <p>User-side code can access data in a shared
       
   216 chunk once it has opened a handle on that chunk. Handles can be passed between
       
   217 user processes using the various handle passing functions. This most common
       
   218 scenario is via client-server Inter Process Communication (IPC). </p> <p><b>Passing
       
   219 a handle from client to server </b> </p> <p>The client passes the handle to
       
   220 the shared chunk as one of the four arguments in a <xref href="GUID-4AD02F14-1142-372F-9D11-224595932034.dita"><apiname>TIpcArgs</apiname></xref> object.
       
   221 The server opens this using the <xref href="GUID-326A2F4D-0E99-31C0-A35D-E8BF45913F07.dita#GUID-326A2F4D-0E99-31C0-A35D-E8BF45913F07/GUID-BE5915FF-4C43-30D8-A6E3-45C33973CD9D"><apiname>RChunk::Open()</apiname></xref> variant
       
   222 with the signature: </p> <codeblock id="GUID-0AFB6DCA-A689-55CD-8B51-18E001822855" xml:space="preserve">RChunk::Open(RMessagePtr2 aMessage,TInt aParam,TBool isReadOnly, TOwnerType aType)
       
   223 </codeblock> <p><b>Passing a handle from server to client </b> </p> <p>The
       
   224 server completes the client message using the chunk handle: </p> <codeblock id="GUID-8CBBC765-9623-508D-8761-A123A4697C7C" xml:space="preserve">RMessagePtr2::Complete(RHandleBase aHandle)</codeblock> <p>The
       
   225 client then assigns the returned handle value to an <xref href="GUID-326A2F4D-0E99-31C0-A35D-E8BF45913F07.dita"><apiname>RChunk</apiname></xref> by
       
   226 calling: </p> <codeblock id="GUID-EC9CE7E0-20B2-5315-9770-0860A3C429DA" xml:space="preserve">RChunk::SetReturnedHandle(TInt aHandleOrError)</codeblock> <p> <b> Note:</b>  </p> <ul>
       
   227 <li id="GUID-B32E3982-9AC8-531E-9109-3CA77F75D4F4"><p>Processes that share
       
   228 data within shared chunks must specify the address of that data as an <i>offset</i> from
       
   229 the start of the chunk, and not as an absolute address. This is because the
       
   230 chunk may appear at different addresses in the address spaces of different
       
   231 user processes. </p> </li>
       
   232 <li id="GUID-BD87DA45-3279-522C-BF23-552A40DFB8FD"><p>Once a chunk is no longer
       
   233 needed for data sharing, user applications should close the handle they have
       
   234 on it. If they do not, the memory mapped by the chunk can never be freed. </p> </li>
       
   235 </ul> <p>See <xref href="GUID-6047DB3F-DC92-51DF-9EEB-00E79E890B54.dita">Using
       
   236 Client/Server</xref>. </p> </section>
       
   237 <section id="GUID-A8FF0519-9FDC-53D5-8BD6-A3AEA6BFDD46"><title>Direct peripheral
       
   238 access to shared chunks</title> <p>When DMA or any other hardware device accesses
       
   239 the physical memory represented by a shared chunk, the contents of CPU memory
       
   240 cache(s) must be synchronised with that memory. Use these functions for this
       
   241 purpose: </p> <ul>
       
   242 <li id="GUID-F1BB9CD1-2D18-5B85-B2DC-C3189C2A82CB"><p> <xref href="GUID-4425E698-EE8A-369B-92CD-09B1CBD2911F.dita#GUID-4425E698-EE8A-369B-92CD-09B1CBD2911F/GUID-5F08DEAA-1237-32DE-AE41-CE7B18230972"><apiname>Cache::SyncMemoryBeforeDmaWrite()</apiname></xref>  </p> </li>
       
   243 <li id="GUID-89FE8A8C-BD27-5A9C-A429-7600CDF2CD76"><p> <xref href="GUID-4425E698-EE8A-369B-92CD-09B1CBD2911F.dita#GUID-4425E698-EE8A-369B-92CD-09B1CBD2911F/GUID-3FF3C567-C1BD-3D4E-97E1-B036456A374E"><apiname>Cache::SyncMemoryBeforeDmaRead()</apiname></xref>  </p> </li>
       
   244 </ul> <p> <b> Note:</b> both these functions take a <xref href="GUID-F58A1C0D-1B36-37EA-8012-1C74B2D12CAD.dita"><apiname>TUint32</apiname></xref> type
       
   245 parameter, identified in the function signatures as <codeph>TUint32 aMapAttr</codeph>.
       
   246 This is the same <codeph>TUint32</codeph> value set on return from calls to
       
   247 either <xref href="GUID-C6946ECB-775F-3EC2-A56F-78F25B9FBE3D.dita#GUID-C6946ECB-775F-3EC2-A56F-78F25B9FBE3D/GUID-79F110C1-2764-34B5-857B-6C0012D2049D"><apiname>Kern::ChunkPhysicalAddress()</apiname></xref> or <xref href="GUID-C6946ECB-775F-3EC2-A56F-78F25B9FBE3D.dita#GUID-C6946ECB-775F-3EC2-A56F-78F25B9FBE3D/GUID-F8D1FB29-7238-3438-951A-6F853C7CF817"><apiname>Kern::ChunkCreate()</apiname></xref>. </p> </section>
       
   248 <section id="GUID-D8E298EA-A4CD-5501-B5F1-B8F0EE93CE84"><title>Example code</title> <p>This
       
   249 section contains code snippets that show shared chunks in use. Most of the
       
   250 code is intended to be part of a device driver. A few snippets show user-side
       
   251 code and the interaction with device driver code. </p> <ul>
       
   252 <li id="GUID-F2F06E9B-4832-5E05-B392-EC0B89CC2813"><p> <xref href="GUID-51514A4B-0220-557B-9F7A-FB110CEFEF10.dita#GUID-51514A4B-0220-557B-9F7A-FB110CEFEF10/GUID-D284D6D0-400D-53D2-9A43-05CEE28DFDC4">Example: Creating a shared chunk</xref>  </p> </li>
       
   253 <li id="GUID-9807283B-B66D-59BE-A6E3-6A9E0A62021D"><p> <xref href="GUID-51514A4B-0220-557B-9F7A-FB110CEFEF10.dita#GUID-51514A4B-0220-557B-9F7A-FB110CEFEF10/GUID-6501F90A-5330-5BC9-A991-A3BECCCA6CDD">Example: Opening a handle to the shared chunk for user-side access</xref>  </p> </li>
       
   254 <li id="GUID-3C59E7E6-FA0C-5487-BEC8-FCA4BBE2524F"><p> <xref href="GUID-51514A4B-0220-557B-9F7A-FB110CEFEF10.dita#GUID-51514A4B-0220-557B-9F7A-FB110CEFEF10/GUID-062C405B-B10F-54A8-8F61-418CAE6019D8">Example: using a DFC to notify destruction of chunk</xref>  </p> </li>
       
   255 <li id="GUID-9FF13AA3-5847-5574-8B0F-81123EB446BE"><p> <xref href="GUID-51514A4B-0220-557B-9F7A-FB110CEFEF10.dita#GUID-51514A4B-0220-557B-9F7A-FB110CEFEF10/GUID-97BF15A2-E74A-51DE-B003-16E1DFF8964E">Example: committing memory</xref>  </p> </li>
       
   256 </ul> <p id="GUID-D284D6D0-400D-53D2-9A43-05CEE28DFDC4"><b>Example: Creating
       
   257 a shared chunk</b> </p> <p>This code snippet shows how a device driver creates
       
   258 a shared chunk. The class <codeph>DMyDevice</codeph> has been given responsibility
       
   259 for creating the chunk: </p> <codeblock id="GUID-FD2DE166-0516-529A-BD0E-8A872968A67A" xml:space="preserve">/**
       
   260 The device or other object making use of shared chunks
       
   261 */
       
   262 class DMyDevice
       
   263     {
       
   264     ...
       
   265     TInt CreateChunk();
       
   266     void CloseChunk();
       
   267 private:
       
   268     void ChunkDestroyed();
       
   269 private:
       
   270     TBool iMemoryInUse;
       
   271     DChunk* iChunk
       
   272     TUint32 iChunkMapAttr;
       
   273     TLinAddr iChunkKernelAddr;
       
   274     ...
       
   275     }</codeblock> <codeblock id="GUID-40DB5E59-11DC-5FC5-B36A-6766132C9A65" xml:space="preserve">/*
       
   276 Address and size of our device's memory
       
   277 */
       
   278 const TPhysAddr KMyDeviceAddress = 0xc1000000;  // Physical address
       
   279 const TInt KMyDeviceMemorySize = 0x10000;
       
   280 
       
   281 /**
       
   282 Create a chunk which maps our device's memory
       
   283 */
       
   284 TInt DMyDevice::CreateChunk()
       
   285     {
       
   286     // Check if our device's memory is already in use
       
   287     if(iMemoryInUse)
       
   288         {
       
   289         // Wait for short while (200ms) in case chunk is being deleted
       
   290         NKern::Sleep(NKern::TimerTicks(200));
       
   291         // Check again
       
   292         if(iMemoryInUse)
       
   293             {
       
   294             // Another part of the system is probably still using our memory, so...
       
   295             return KErrInUse;
       
   296             }
       
   297         }
       
   298 
       
   299     // Enter critical section so we can't die and leak the objects we are creating
       
   300     // I.e. the TChunkCleanup and DChunk (Shared Chunk)
       
   301     NKern::ThreadEnterCS();
       
   302 
       
   303     // Create chunk cleanup object
       
   304     TChunkCleanup* cleanup = new iChunkCleanup(this);
       
   305     if(!cleanup)
       
   306         {
       
   307         NKern::ThreadLeaveCS();
       
   308         return KErrNoMemory;
       
   309         }
       
   310 
       
   311     // Create the chunk
       
   312     TChunkCreateInfo info;
       
   313     info.iType         = TChunkCreateInfo::ESharedKernelMultiple;
       
   314     info.iMaxSize      = KMyDeviceMemorySize;
       
   315     info.iMapAttr      = EMapAttrFullyBlocking; // No caching
       
   316     info.iOwnsMemory   = EFalse; // We'll be using our own devices memory
       
   317     info.iDestroyedDfc = cleanup;
       
   318     DChunk* chunk;
       
   319     TInt r = Kern::ChunkCreate(info, chunk, iChunkKernelAddr, iChunkMapAttr);
       
   320     if(r!=KErrNone)
       
   321         {
       
   322         delete cleanup;
       
   323         NKern::ThreadLeaveCS();
       
   324         return r;
       
   325         }
       
   326 
       
   327     // Map our device's memory into the chunk (at offset 0)
       
   328 
       
   329     r = Kern::ChunkCommitPhysical(chunk,0,KMyDeviceMemorySize,KMyDeviceAddress);
       
   330     if(r!=KErrNone)
       
   331         {
       
   332         // Commit failed so tidy-up...
       
   333 
       
   334         // We, can't delete 'cleanup' because it is now owned by the chunk and will
       
   335         // get run when the chunk is destroyed. Instead, we have to Cancel it, which
       
   336         // prevents it from doing anything when it does run.
       
   337         cleanup-&gt;Cancel()
       
   338         // Close chunk, which will then get deleted at some point
       
   339         Kern::ChunkClose(chunk);
       
   340         }
       
   341     else
       
   342         {
       
   343         // Commit succeeded so flag memory in use and store chunk pointer
       
   344         iMemoryInUse = ETrue;
       
   345         iChunk = chunk;
       
   346         }
       
   347 
       
   348     // Can leave critical section now that we have saved pointers to created objects
       
   349     NKern::ThreadLeaveCS();
       
   350 
       
   351     return r;
       
   352     }
       
   353 
       
   354 /**
       
   355 Close the chunk which maps our device's memory
       
   356 */
       
   357 TInt DMyDevice::CloseChunk()
       
   358     {
       
   359     // Enter critical section so we can't die whilst owning the chunk pointer
       
   360     NKern::ThreadEnterCS();
       
   361 
       
   362     // Atomically get pointer to our chunk and NULL the iChunk member
       
   363     DChunk* chunk = (DChunk*)NKern::SafeSwap(NULL,(TAny*&amp;)iChunk);
       
   364 
       
   365     // Close chunk
       
   366     if(chunk)
       
   367        Kern::CloseChunk(chunk);
       
   368 
       
   369     // Can leave critical section now
       
   370     NKern::ThreadLeaveCS();
       
   371     }
       
   372 </codeblock> <p><b>Implementation notes </b> </p> <ul>
       
   373 <li id="GUID-A587088F-889D-58F7-973D-AD6C471B43E2"><p>a <xref href="GUID-51F7DBCF-BFB6-31F9-8882-5D263A1AD4B4.dita"><apiname>TChunkCreateInfo</apiname></xref> object
       
   374 is created, populated and passed to <xref href="GUID-C6946ECB-775F-3EC2-A56F-78F25B9FBE3D.dita#GUID-C6946ECB-775F-3EC2-A56F-78F25B9FBE3D/GUID-F8D1FB29-7238-3438-951A-6F853C7CF817"><apiname>Kern::ChunkCreate()</apiname></xref>.
       
   375 This is information that Symbian platform needs to create the chunk. To create
       
   376 a <i>shared</i> chunk, <xref href="GUID-51F7DBCF-BFB6-31F9-8882-5D263A1AD4B4.dita#GUID-51F7DBCF-BFB6-31F9-8882-5D263A1AD4B4/GUID-4384AF76-CECE-3B86-BE92-375C1DEA36DA"><apiname>TChunkCreateInfo::iType</apiname></xref> must be
       
   377 set to <xref href="GUID-51F7DBCF-BFB6-31F9-8882-5D263A1AD4B4.dita#GUID-51F7DBCF-BFB6-31F9-8882-5D263A1AD4B4/GUID-B00A3693-50B6-3A84-89E0-B06D9ABE82ED"><apiname>TChunkCreateInfo::ESharedKernelMultiple</apiname></xref>. </p> </li>
       
   378 <li id="GUID-F2EB6952-CAFA-5CB0-BB86-3C77C46C9EEA"><p>If the device architecture
       
   379 allowed the device driver function <codeph>DMyDevice::CreateChunk()</codeph> to
       
   380 be called in a re-entrant manner, you would need to protect this code using
       
   381 a mutex. Such a situation might arise when a logical channel is shared between
       
   382 two threads, or two logical channels are created on the same device. There
       
   383 may also be other cases where a mutex is needed. </p> <p>See also: </p> <ul>
       
   384 <li id="GUID-B5A971C3-B630-5944-851C-86D4285D3C90"><p> <xref href="GUID-EAA6A9FB-A470-550C-B7B4-FF68A733A2D5.dita#GUID-EAA6A9FB-A470-550C-B7B4-FF68A733A2D5/GUID-F5B59A23-48E0-5596-B589-10DD2549F124">The Symbian platform mutex</xref>  </p> </li>
       
   385 <li id="GUID-0618C6AD-DB19-50A6-979B-D2D7C7CA0413"><p> <xref href="GUID-C6946ECB-775F-3EC2-A56F-78F25B9FBE3D.dita#GUID-C6946ECB-775F-3EC2-A56F-78F25B9FBE3D/GUID-FEBBDA4F-412E-3AE5-9098-8E2F6BF3E969"><apiname>Kern::MutexCreate()</apiname></xref>  </p> </li>
       
   386 <li id="GUID-7FA55315-7403-5CAD-9E84-73A7F8D3DF3A"><p> <xref href="GUID-C6946ECB-775F-3EC2-A56F-78F25B9FBE3D.dita#GUID-C6946ECB-775F-3EC2-A56F-78F25B9FBE3D/GUID-1F0C28A8-9E9A-3AA3-A441-BA8406B3A06A"><apiname>Kern::MutexWait()</apiname></xref>  </p> </li>
       
   387 <li id="GUID-3DC20F30-767F-5D3F-8013-2976AB6B2991"><p> <xref href="GUID-C6946ECB-775F-3EC2-A56F-78F25B9FBE3D.dita#GUID-C6946ECB-775F-3EC2-A56F-78F25B9FBE3D/GUID-B8080F86-1342-31EA-9A28-205354CA0CB9"><apiname>Kern::MutexSignal()</apiname></xref>  </p> </li>
       
   388 </ul> </li>
       
   389 <li id="GUID-A68113CF-C792-59A7-94C3-D2214E065CF6"><p>The line: </p> <codeblock id="GUID-519F054D-429E-5B64-B8FA-34F48E85E1B9" xml:space="preserve">info.iDestroyedDfc = cleanup;</codeblock> <p>in
       
   390 the function <codeph>DMyDevice::CreateChunk()</codeph> and code following
       
   391 the comment </p> <codeblock id="GUID-C1FCC780-1BD1-5E29-9089-B59434804335" xml:space="preserve">// Create chunk cleanup object</codeblock> <p>sets
       
   392 the DFC that runs when the shared chunk is finally closed. See <xref href="GUID-51514A4B-0220-557B-9F7A-FB110CEFEF10.dita#GUID-51514A4B-0220-557B-9F7A-FB110CEFEF10/GUID-062C405B-B10F-54A8-8F61-418CAE6019D8">Example: using a DFC to notify destruction of chunk</xref> for the DFC code
       
   393 itself. </p> </li>
       
   394 </ul> <p id="GUID-6501F90A-5330-5BC9-A991-A3BECCCA6CDD"><b>Example: Opening
       
   395 a handle to the shared chunk for user-side access</b> </p> <p>These code snippets
       
   396 show user-side code making a request to a device driver to open handles on
       
   397 two shared chunks. </p> <p>The code snippets assume that the chunks have already
       
   398 been created. </p> <p><b>User-side</b> </p> <p>The user-side interface to
       
   399 a device driver is always a class derived from <xref href="GUID-6FBFA078-8253-3E24-B1F8-5F75E86C3066.dita"><apiname>RBusLogicalChannel</apiname></xref>,
       
   400 and is provided by the device driver. Here, this is the <codeph>RMyDevice</codeph> class.
       
   401 In real code, the class would offer much more functionality, but only the
       
   402 relevant function members and data members are shown: </p> <codeblock id="GUID-CB639C9A-900F-5344-B50F-7DC190D714EB" xml:space="preserve">/**
       
   403 Client (user-side) interface to the device driver.
       
   404 */
       
   405 class RMyDevice : public RBusLogicalChannel
       
   406     {
       
   407     ...
       
   408 public:
       
   409     TInt OpenIoChunks(RChunk&amp; aInputChunk,RChunk&amp; aOutputChunk);
       
   410     ... 
       
   411 private:
       
   412     /** Structure to hold information about the i/o buffers */
       
   413     class TIoChunkInfo
       
   414         {
       
   415     public:
       
   416         TInt iInputChunkHandle;
       
   417         TInt iOutputChunkHandle;
       
   418         };
       
   419     // Kernel-side channel class is a friend...
       
   420     friend class DMyDeviceChannel; 
       
   421     ...
       
   422     };
       
   423 </codeblock> <p>You call the function <codeph>OpenIoChunks()</codeph> to: </p> <ul>
       
   424 <li id="GUID-46625099-EA5D-519C-A9F3-BC6AD97AB41A"><p>issue a request to the
       
   425 driver to create handles to two chunks </p> </li>
       
   426 <li id="GUID-BAA515D0-FA3A-5D6B-807C-5B562E8B9387"><p>get handles to those
       
   427 shared chunks so that they can be accessed by user-side code. </p> </li>
       
   428 </ul> <codeblock id="GUID-42B88530-E7A7-5F5D-A9D4-2026E3E4F3E4" xml:space="preserve">TInt RMyDevice::OpenIoChunks(RChunk&amp; aInputChunk,RChunk&amp; aOutputChunk)
       
   429     {
       
   430     // Send request to driver to create chunk handles.
       
   431     TIoChunkInfo info;
       
   432     TInt r=DoControl(EOpenIoChunks,(TAny*)&amp;info);
       
   433     // Set the handles for the chunks
       
   434     aInputChunk.SetHandle(info.iInputChunkHandle);
       
   435     aOutputChunk.SetHandle(info.iOutputChunkHandle);
       
   436 
       
   437     return r;
       
   438     }
       
   439 </codeblock> <p><b>Implementation notes </b> </p> <ul>
       
   440 <li id="GUID-3758237B-4806-5852-835C-1288F368BBEE"><p>The request is passed
       
   441 to the driver as a synchronous call; it calls the base class function <xref href="GUID-6FBFA078-8253-3E24-B1F8-5F75E86C3066.dita#GUID-6FBFA078-8253-3E24-B1F8-5F75E86C3066/GUID-D774DE92-6431-374A-A1F6-1C7045BD4FE5"><apiname>RBusLogicalChannel::DoControl()</apiname></xref>.
       
   442 This means that the call does not return until the driver has created (or
       
   443 failed to create) the handles to the shared chunks. The call is synchronous
       
   444 because the creation of the handles does not depend on the hardware controlled
       
   445 by the driver, so there should be minimal delay in its execution. </p> </li>
       
   446 <li id="GUID-F8E261B0-D768-5157-B6FA-6B51B6829E47"><p>The driver returns the
       
   447 handle <i>numbers</i> in the <codeph>TIoChunkInfo</codeph> object; specifically
       
   448 in its <codeph>iInputChunkHandle</codeph> and <codeph>iOutputChunkHandle</codeph> data
       
   449 members. </p> <p>To access the shared chunks, user-side code needs handles
       
   450 to them. Handles to chunks are <xref href="GUID-326A2F4D-0E99-31C0-A35D-E8BF45913F07.dita"><apiname>RChunk</apiname></xref> objects. </p> <p>The
       
   451 final step is to set the returned handle <i>numbers</i> into the <codeph>RChunk</codeph> objects
       
   452 by calling <codeph>SetHandle()</codeph>. This function is provided by <codeph>RChunk</codeph>'s
       
   453 base class <xref href="GUID-727D2B62-09A9-3CBC-AB6F-591E52EC68EB.dita"><apiname>RHandleBase</apiname></xref>. </p> <p>See <xref href="GUID-2EAAE194-FAE1-5545-A678-72973E9B72A7.dita">handles</xref> for
       
   454 background information. </p> </li>
       
   455 <li id="GUID-57FFB715-A05B-5E0D-8354-094018C5AEE5"><p>In this example the
       
   456 return value from <xref href="GUID-6FBFA078-8253-3E24-B1F8-5F75E86C3066.dita#GUID-6FBFA078-8253-3E24-B1F8-5F75E86C3066/GUID-D774DE92-6431-374A-A1F6-1C7045BD4FE5"><apiname>RBusLogicalChannel::DoControl()</apiname></xref> is not
       
   457 checked. In practice you need to do so. </p> </li>
       
   458 </ul> <fig id="GUID-2D81B150-2273-5474-9E33-2C7CE236FAD8">
       
   459 <title>Shared chunks implementation</title>
       
   460 <image href="GUID-52B8098A-7695-5EA6-B58F-D730A445C583_d0e77443_href.png" placement="inline"/>
       
   461 </fig> <p><b> Device driver (kernel) side </b> </p> <p>This is example code
       
   462 snippet shows the device driver side handling of the request made by the user-side
       
   463 to open handles on two shared chunks. </p> <p>The request is handled by the <codeph>OpenIoChunks()</codeph> function
       
   464 in the device driver's logical channel. The logical channel is represented
       
   465 by a class derived from <xref href="GUID-E7550422-5121-3393-A85E-BB797969CD2A.dita"><apiname>DLogicalChannelBase</apiname></xref>. In this example,
       
   466 this is the <codeph>DMyDeviceChannel</codeph> class. </p> <p>Details of how
       
   467 a user-side call to <codeph>RMyDevice::OpenIoChunks()</codeph> results in
       
   468 a call to the driver's <codeph>DMyDeviceChannel::OpenIoChunks()</codeph> function
       
   469 are not shown. <xref href="GUID-0956CE5E-C02B-5EEE-890A-5E8E84A8D9A1.dita#GUID-0956CE5E-C02B-5EEE-890A-5E8E84A8D9A1/GUID-AB757BD9-80A4-53DE-82D8-D9BE8A252C9F">Passing
       
   470 requests from user-side to kernel-side</xref> in <xref href="GUID-0956CE5E-C02B-5EEE-890A-5E8E84A8D9A1.dita">The
       
   471 Logical Channel</xref> explains the principles. </p> <codeblock id="GUID-B55DA6B8-A38F-5ED6-A415-DBB027D30870" xml:space="preserve">/**
       
   472   Kernel-side Logical Channel for 'MyDevice'
       
   473 */
       
   474 class DMyDeviceChannel : public DLogicalChannelBase
       
   475     {
       
   476     ...
       
   477 private:
       
   478     TInt OpenIoChunks(RMyDevice::TIoChunkInfo* aIoChunkInfoForClient);
       
   479 private:
       
   480     DChunk* iInputChunk;
       
   481     TInt iInputChunkSize;
       
   482     DChunk* iOutputChunk;
       
   483     TInt iOutputChunkSize;
       
   484     ...
       
   485     };
       
   486 </codeblock> <p>The following code snippet is the implementation of <codeph>DMyDeviceChannel::OpenIoChunks()</codeph>. </p> <codeblock id="GUID-E344116F-8C10-5226-9547-5F0ABD16D831" xml:space="preserve">/**
       
   487   Called by logical channel to service a client request for i/o chunk handles
       
   488 */
       
   489 TInt DMyDeviceChannel::OpenIoChunks(RMyDevice::TIoChunkInfo* aIoChunkInfo)
       
   490     {
       
   491     // Local info structure we will fill in
       
   492     RMyDevice::TIoChunkInfo info;
       
   493 
       
   494     // Need to be in critical section whilst creating handles
       
   495     NKern::ThreadEnterCS();
       
   496 
       
   497     // Make handle to iInputChunk for current thread
       
   498     TInt r = Kern::MakeHandleAndOpen(NULL, iInputChunk); 
       
   499     // r = +ve value for a handle, -ve value is error code
       
   500     if(r&gt;=0) 
       
   501         {
       
   502         // Store InputChunk handle
       
   503         info.iInputChunkHandle = r;
       
   504 
       
   505         // Make handle to iOutputChunk for current thread
       
   506         r = Kern::MakeHandleAndOpen(NULL, iOutputChunk); 
       
   507         // r = +ve value for a handle, -ve value is error code
       
   508         if(r&gt;=0) 
       
   509             {
       
   510             // Store OutputChunk handle
       
   511             info.iOutputChunkHandle = r;
       
   512             // Signal we succeeded...
       
   513             r = KErrNone;
       
   514             }
       
   515         else
       
   516             {
       
   517             // Error, so cleanup the handle we created for iInputChunk
       
   518             Kern::CloseHandle(NULL,info.iInputChunkHandle);
       
   519             }
       
   520         }
       
   521 
       
   522     // Leave critical section before writing info to client because throwing an
       
   523     // exception whilst in a critical section is fatal to the system.
       
   524     NKern::ThreadLeaveCS();
       
   525 
       
   526     // If error, zero contents of info structure.
       
   527     // (Zero is usually a safe value to return on error for most data types,
       
   528     // and for object handles this is same as KNullHandle)
       
   529     if(r!=KErrNone)
       
   530         memclr(&amp;info,sizeof(info));
       
   531 
       
   532     // Write info to client memory
       
   533     kumemput32(aIoChunkInfo,&amp;info,sizeof(info));
       
   534 
       
   535     return r;
       
   536     }
       
   537 </codeblock> <p><b>Implementation notes </b> </p> <ul>
       
   538 <li id="GUID-396C4C6F-C6ED-5796-8B68-13A2E25FF365"><p>The function calls <xref href="GUID-C6946ECB-775F-3EC2-A56F-78F25B9FBE3D.dita#GUID-C6946ECB-775F-3EC2-A56F-78F25B9FBE3D/GUID-BA56B205-60D8-326E-8340-3F78CCEA3DD1"><apiname>Kern::MakeHandleAndOpen()</apiname></xref> twice,
       
   539 once for each shared chunk. A NULL value is passed as the first parameter
       
   540 in both calls to this function instead of an explicit <codeph>DThread</codeph> object.
       
   541 This creates the handles for the current thread. Although this code is running
       
   542 in kernel mode, the context remains the user thread. </p> </li>
       
   543 <li id="GUID-B0D3721A-A5A8-5A17-A402-C84A087DC921"><p>The first handle created
       
   544 is closed if the second handle cannot be created: </p> <codeblock id="GUID-8B73E41A-8BEF-503A-8A22-13F2258BC380" xml:space="preserve">if(r&gt;=0) 
       
   545             {
       
   546             ...
       
   547             }
       
   548         else
       
   549             {
       
   550             // Error, so cleanup the handle we created for iInputChunk
       
   551             Kern::CloseHandle(NULL,info.iInputChunkHandle);
       
   552             }</codeblock> </li>
       
   553 <li id="GUID-396AE759-ACC8-5F7E-AF36-37A7A2BDB855"><p>The handle values are
       
   554 written back into the <codeph>TIoChunkInfo</codeph> structure using the <xref href="GUID-D141C3C4-F2F6-37DF-BDF6-63DDE9052FA0.dita"><apiname>kumemput32()</apiname></xref> function.
       
   555 See the EKA2 references in <xref href="GUID-F46B87B7-97A9-530B-BAC4-EF1DB9C91E39.dita#GUID-F46B87B7-97A9-530B-BAC4-EF1DB9C91E39/GUID-4A7BCB91-C58B-597F-85B6-74463BE9BC04">Accessing
       
   556 User Memory</xref> in <xref href="GUID-F46B87B7-97A9-530B-BAC4-EF1DB9C91E39.dita">Migration
       
   557 Tutorial: EKA1 Device Driver to Kernel Architecture 2</xref>. </p> </li>
       
   558 </ul> <p id="GUID-062C405B-B10F-54A8-8F61-418CAE6019D8"><b>Example: Using
       
   559 a DFC to notify destruction of a chunk</b> </p> <p>This set of code snippets
       
   560 shows how to set up a DFC that notifies a device driver when a shared chunk
       
   561 has finally been destroyed. </p> <codeblock id="GUID-F75EE51B-EC55-57C1-B2C6-D68D44B34069" xml:space="preserve">/**
       
   562 Example class suitable for use as a 'Chunk Destroyed DFC' when
       
   563 creating Shared Chunks with Kern::ChunkCreate()
       
   564 */
       
   565 class TChunkCleanup : private TDfc
       
   566     {
       
   567 public:
       
   568     TChunkCleanup(DMyDevice* aDevice);
       
   569     void Cancel();
       
   570 private:
       
   571     static void ChunkDestroyed(TChunkCleanup* aSelf);
       
   572 private:
       
   573     DMyDevice* iDevice;
       
   574     };
       
   575 
       
   576 /**
       
   577 Contruct a Shared Chunk cleanup object which will signal the specified device
       
   578 when a chunk is destroyed.
       
   579 */
       
   580 TChunkCleanup::TChunkCleanup(DMyDevice* aDevice)
       
   581     : TDfc((TDfcFn)TChunkCleanup::ChunkDestroyed,this,Kern::SvMsgQue(),0)
       
   582     , iDevice(aDevice)
       
   583     {}
       
   584 
       
   585 /**
       
   586 Cancel the action of the cleanup object.
       
   587 */
       
   588 void TChunkCleanup::Cancel()
       
   589     {
       
   590     // Clear iDevice which means that when the DFC gets queued on chunk destruction
       
   591     // our ChunkDestroyed method will do nothing other than cleanup itself.
       
   592     iDevice = NULL;
       
   593     }
       
   594 
       
   595 /**
       
   596 Callback function called when the DFC runs, i.e. when a chunk is destroyed.
       
   597 */
       
   598 void TChunkCleanup::ChunkDestroyed(TChunkCleanup* aSelf)
       
   599     {
       
   600     DMyDevice* device = aSelf-&gt;iDevice;
       
   601     // If we haven't been Cancelled...
       
   602     if(device)
       
   603         {
       
   604         // Perform any cleanup action required. In this example we call a method
       
   605         // on 'MyDevice' which encapsulates this.
       
   606         device-&gt;ChunkDestroyed();
       
   607         }
       
   608 
       
   609     // We've finished so now delete ourself
       
   610     delete aSelf;
       
   611     }
       
   612 </codeblock> <p><b>Implementation notes </b> </p> <ul>
       
   613 <li id="GUID-3387037D-9BBC-5A07-A180-FC2DAB6F6503"><p>The DFC is an item of
       
   614 information that is passed to <xref href="GUID-C6946ECB-775F-3EC2-A56F-78F25B9FBE3D.dita#GUID-C6946ECB-775F-3EC2-A56F-78F25B9FBE3D/GUID-F8D1FB29-7238-3438-951A-6F853C7CF817"><apiname>Kern::ChunkCreate()</apiname></xref> when
       
   615 the shared chunk is created. See <xref href="GUID-51514A4B-0220-557B-9F7A-FB110CEFEF10.dita#GUID-51514A4B-0220-557B-9F7A-FB110CEFEF10/GUID-D284D6D0-400D-53D2-9A43-05CEE28DFDC4">Example:
       
   616 Creating a shared chunk</xref> to see how the two sets of code connect. </p> </li>
       
   617 <li id="GUID-CB5AE321-CF79-543D-9CA2-DDF1B0B115EC"><p>Ensure that the code
       
   618 implementing this DFC is still loaded when the DFC runs. As you cannot know
       
   619 when a chunk will be destroyed, the code should reside in a kernel extension. </p> </li>
       
   620 </ul> <p id="GUID-97BF15A2-E74A-51DE-B003-16E1DFF8964E"><b>Example: committing
       
   621 memory</b> </p> <p>This code snippet shows how memory is committed. It is
       
   622 based on the implementation of the class <codeph>DBuffers</codeph>, which
       
   623 represents a group of buffers hosted by a single chunk. </p> <codeblock id="GUID-9768851E-648B-501D-9AA5-1922EB428EEC" xml:space="preserve">/**
       
   624   Class representing a group of buffers in the same chunk
       
   625 */
       
   626 class DBuffers
       
   627     {
       
   628 public:
       
   629     DBuffers();
       
   630     ~DBuffers();
       
   631     TInt Create(TInt aBufferSize,TInt aNumBuffers);
       
   632 public:
       
   633     DChunk* iChunk;             /**&lt; The chunk containing the buffers. */
       
   634     TLinAddr iChunkKernelAddr;  /**&lt; Address of chunk start in kernel process */
       
   635     TUint32 iChunkMapAttr;      /**&lt; MMU mapping attributes used for chunk */
       
   636     TInt iBufferSize;           /**&lt; Size of each buffer in bytes */
       
   637     TInt iOffsetToFirstBuffer;  /**&lt; Offset within chunk of the first buffer */
       
   638     TInt iOffsetBetweenBuffers; /**&lt; Offset in bytes between consecutive buffers */
       
   639     };</codeblock> <codeblock id="GUID-CBC59647-DEA3-52AC-B7BD-BF15F29BB0E7" xml:space="preserve">/** Constructor */
       
   640 DBuffers::DBuffers()
       
   641     : iChunk(NULL)
       
   642     {}
       
   643 
       
   644 /** Destructor */
       
   645 DBuffers::~DBuffers()
       
   646     {
       
   647     if(iChunk) Kern::ChunkClose(iChunk);
       
   648     }
       
   649 
       
   650 /**
       
   651   Create the chunk and commit memory for all the buffers.
       
   652   @param aBuffserSize Size in bytes of each buffer
       
   653   @param aNumBuffers Number of buffers to create
       
   654 */
       
   655 TInt DBuffers::Create(TInt aBufferSize,TInt aNumBuffers)
       
   656     {
       
   657     // Round buffer size up to MMU page size
       
   658     aBufferSize = Kern::RoundToPageSize(aBufferSize);
       
   659     iBufferSize = aBufferSize;
       
   660 
       
   661     // Size of one MMU page
       
   662     TInt pageSize = Kern::RoundToPageSize(1);
       
   663 
       
   664     // We will space our buffers with one empty MMU page between each.
       
   665     // This helps detect buffer overflows...
       
   666 
       
   667     // First buffer starts one MMU page into chunk
       
   668     iOffsetToFirstBuffer = pageSize; 
       
   669 
       
   670     // Each buffer will be spaced apart by this much
       
   671     iOffsetBetweenBuffers = aBufferSize+pageSize;
       
   672 
       
   673     // Calculate chunk size
       
   674     TUint64 chunkSize = TUint64(iOffsetBetweenBuffers)*aNumBuffers+pageSize;
       
   675 
       
   676     // Check size is sensible
       
   677     if(chunkSize&gt;(TUint64)KMaxTInt)
       
   678         return KErrNoMemory;  // Need more than 2GB of memory!
       
   679 
       
   680     // Enter critical section whilst creating objects
       
   681     NKern::ThreadEnterCS();
       
   682 
       
   683     // Create the chunk
       
   684     TChunkCreateInfo info;
       
   685     info.iType         = TChunkCreateInfo::ESharedKernelMultiple;
       
   686     info.iMaxSize      = (TInt)chunkSize;
       
   687     info.iMapAttr      = EMapAttrCachedMax; // Full caching
       
   688     info.iOwnsMemory   = ETrue; // Use memory from system's free pool
       
   689     info.iDestroyedDfc = NULL;
       
   690     TInt r = Kern::ChunkCreate(info, iChunk, iChunkKernelAddr, iChunkMapAttr);
       
   691     if(r==KErrNone)
       
   692         {
       
   693         // Commit memory for each buffer...
       
   694 
       
   695         TInt offset = iOffsetToFirstBuffer; // Offset within chunk for first buffer
       
   696 
       
   697         // Repeat for each buffer required...
       
   698         while(aNumBuffers--)
       
   699             {
       
   700             // Commit memory at 'offset' within chunk
       
   701             r = Kern::ChunkCommit(iChunk,offset,aBufferSize);
       
   702             if(r!=KErrNone)
       
   703                 break;
       
   704 
       
   705             // Move 'offset' on to next buffer
       
   706             offset += iOffsetBetweenBuffers;
       
   707             }
       
   708 
       
   709         if(r!=KErrNone)
       
   710             {
       
   711             // On error, throw away the chunk we have created
       
   712             Kern::ChunkClose(iChunk);
       
   713             iChunk = NULL; // To indicate that 'this' doesn't have any valid buffers
       
   714             }
       
   715         }
       
   716 
       
   717     // Finished
       
   718     NKern::ThreadLeaveCS();
       
   719     return r;
       
   720     }
       
   721 </codeblock> </section>
       
   722 </conbody></concept>