|
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&)</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->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*&)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& aInputChunk,RChunk& 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& aInputChunk,RChunk& aOutputChunk) |
|
429 { |
|
430 // Send request to driver to create chunk handles. |
|
431 TIoChunkInfo info; |
|
432 TInt r=DoControl(EOpenIoChunks,(TAny*)&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>=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>=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(&info,sizeof(info)); |
|
531 |
|
532 // Write info to client memory |
|
533 kumemput32(aIoChunkInfo,&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>=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->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->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; /**< The chunk containing the buffers. */ |
|
634 TLinAddr iChunkKernelAddr; /**< Address of chunk start in kernel process */ |
|
635 TUint32 iChunkMapAttr; /**< MMU mapping attributes used for chunk */ |
|
636 TInt iBufferSize; /**< Size of each buffer in bytes */ |
|
637 TInt iOffsetToFirstBuffer; /**< Offset within chunk of the first buffer */ |
|
638 TInt iOffsetBetweenBuffers; /**< 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>(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> |