VirtualBox

source: vbox/trunk/include/VBox/pdmasynccompletion.h@ 13835

Last change on this file since 13835 was 13835, checked in by vboxsync, 16 years ago

s/VBOX_SUCCESS/RT_SUCCESS/g s/VBOX_FAILURE/RT_FAILURE/g - VBOX_SUCCESS and VBOX_FAILURE have *NOT* been retired (because old habbits die hard) just sligtly deprecated.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 19.4 KB
Line 
1/* $Id: pdmasynccompletion.h 13835 2008-11-05 02:34:43Z vboxsync $ */
2/** @file
3 * PDM - Pluggable Device Manager, Async I/O Completion.
4 */
5
6/*
7 * Copyright (C) 2007 Sun Microsystems, Inc.
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * The contents of this file may alternatively be used under the terms
18 * of the Common Development and Distribution License Version 1.0
19 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
20 * VirtualBox OSE distribution, in which case the provisions of the
21 * CDDL are applicable instead of those of the GPL.
22 *
23 * You may elect to license modified versions of this file under the
24 * terms and conditions of either the GPL or the CDDL or both.
25 *
26 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
27 * Clara, CA 95054 USA or visit http://www.sun.com if you need
28 * additional information or have any questions.
29 */
30
31#ifndef ___VBox_pdmasynccompletion_h
32#define ___VBox_pdmasynccompletion_h
33
34#include <VBox/types.h>
35#include <VBox/err.h>
36#include <iprt/assert.h>
37
38__BEGIN_DECLS
39
40/** @defgroup grp_pdm_async_completion The PDM Async I/O Completion API
41 * @ingroup grp_pdm
42 * @{
43 */
44
45/** Pointer to a PDM async completion template handle. */
46typedef struct PDMASYNCCOMPLETIONTEMPLATE *PPDMASYNCCOMPLETIONTEMPLATE;
47/** Pointer to a PDM async completion template handle pointer. */
48typedef PPDMASYNCCOMPLETIONTEMPLATE *PPPDMASYNCCOMPLETIONTEMPLATE;
49
50/** Pointer to a PDM async completion task handle. */
51typedef struct PDMASYNCCOMPLETIONTASK *PPDMASYNCCOMPLETIONTASK;
52/** Pointer to a PDM async completion task handle pointer. */
53typedef PPDMASYNCCOMPLETIONTASK *PPPDMASYNCCOMPLETIONTASK;
54
55
56/**
57 * Completion callback for devices.
58 *
59 * @param pDevIns The device instance.
60 * @param pTask Pointer to the completion task.
61 * The task is at the time of the call setup to be resumed. So, the callback must
62 * call PDMR3AsyncCompletionSuspend or PDMR3AsyncCompletionDestroy if any other
63 * action is wanted upon return.
64 * @param pvCtx Pointer to any additional, OS specific, completion context. TBD.
65 * @param pvUser User argument.
66 */
67typedef DECLCALLBACK(void) FNPDMASYNCCOMPLETEDEV(PPDMDEVINS pDevIns, PPDMASYNCCOMPLETIONTASK pTask, void *pvCtx, void *pvUser);
68/** Pointer to a FNPDMASYNCCOMPLETEDEV(). */
69typedef FNPDMASYNCCOMPLETEDEV *PFNPDMASYNCCOMPLETEDEV;
70
71
72/**
73 * Completion callback for drivers.
74 *
75 * @param pDrvIns The driver instance.
76 * @param pTask Pointer to the completion task.
77 * The task is at the time of the call setup to be resumed. So, the callback must
78 * call PDMR3AsyncCompletionSuspend or PDMR3AsyncCompletionDestroy if any other
79 * action is wanted upon return.
80 * @param pvCtx Pointer to any additional, OS specific, completion context. TBD.
81 * @param pvUser User argument.
82 */
83typedef DECLCALLBACK(void) FNPDMASYNCCOMPLETEDRV(PPDMDRVINS pDrvIns, PPDMASYNCCOMPLETIONTASK pTask, void *pvCtx, void *pvUser);
84/** Pointer to a FNPDMASYNCCOMPLETEDRV(). */
85typedef FNPDMASYNCCOMPLETEDRV *PFNPDMASYNCCOMPLETEDRV;
86
87
88/**
89 * Completion callback for USB devices.
90 *
91 * @param pUsbIns The USB device instance.
92 * @param pTask Pointer to the completion task.
93 * The task is at the time of the call setup to be resumed. So, the callback must
94 * call PDMR3AsyncCompletionSuspend or PDMR3AsyncCompletionDestroy if any other
95 * action is wanted upon return.
96 * @param pvCtx Pointer to any additional, OS specific, completion context. TBD.
97 * @param pvUser User argument.
98 */
99typedef DECLCALLBACK(void) FNPDMASYNCCOMPLETEUSB(PPDMUSBINS pUsbIns, PPDMASYNCCOMPLETIONTASK pTask, void *pvCtx, void *pvUser);
100/** Pointer to a FNPDMASYNCCOMPLETEUSB(). */
101typedef FNPDMASYNCCOMPLETEUSB *PFNPDMASYNCCOMPLETEUSB;
102
103
104/**
105 * Completion callback for internal.
106 *
107 * @param pVM Pointer to the shared VM structure.
108 * @param pTask Pointer to the completion task.
109 * The task is at the time of the call setup to be resumed. So, the callback must
110 * call PDMR3AsyncCompletionSuspend or PDMR3AsyncCompletionDestroy if any other
111 * action is wanted upon return.
112 * @param pvCtx Pointer to any additional, OS specific, completion context. TBD.
113 * @param pvUser User argument for the task.
114 * @param pvUser2 User argument for the template.
115 */
116typedef DECLCALLBACK(void) FNPDMASYNCCOMPLETEINT(PVM pVM, PPDMASYNCCOMPLETIONTASK pTask, void *pvCtx, void *pvUser, void *pvUser2);
117/** Pointer to a FNPDMASYNCCOMPLETEINT(). */
118typedef FNPDMASYNCCOMPLETEINT *PFNPDMASYNCCOMPLETEINT;
119
120
121/**
122 * Creates a async completion template for a device instance.
123 *
124 * The template is used when creating new completion tasks.
125 *
126 * @returns VBox status code.
127 * @param pVM Pointer to the shared VM structure.
128 * @param pDevIns The device instance.
129 * @param ppTemplate Where to store the template pointer on success.
130 * @param pfnCompleted The completion callback routine.
131 * @param pszDesc Description.
132 */
133VMMR3DECL(int) PDMR3AsyncCompletionTemplateCreateDevice(PVM pVM, PPDMDEVINS pDevIns, PPPDMASYNCCOMPLETIONTEMPLATE ppTemplate, PFNPDMASYNCCOMPLETEDEV pfnCompleted, const char *pszDesc);
134
135/**
136 * Creates a async completion template for a driver instance.
137 *
138 * The template is used when creating new completion tasks.
139 *
140 * @returns VBox status code.
141 * @param pVM Pointer to the shared VM structure.
142 * @param pDrvIns The driver instance.
143 * @param ppTemplate Where to store the template pointer on success.
144 * @param pfnCompleted The completion callback routine.
145 * @param pszDesc Description.
146 */
147VMMR3DECL(int) PDMR3AsyncCompletionTemplateCreateDriver(PVM pVM, PPDMDRVINS pDrvIns, PPPDMASYNCCOMPLETIONTEMPLATE ppTemplate, PFNPDMASYNCCOMPLETEDRV pfnCompleted, const char *pszDesc);
148
149/**
150 * Creates a async completion template for a USB device instance.
151 *
152 * The template is used when creating new completion tasks.
153 *
154 * @returns VBox status code.
155 * @param pVM Pointer to the shared VM structure.
156 * @param pUsbIns The USB device instance.
157 * @param ppTemplate Where to store the template pointer on success.
158 * @param pfnCompleted The completion callback routine.
159 * @param pszDesc Description.
160 */
161VMMR3DECL(int) PDMR3AsyncCompletionTemplateCreateUsb(PVM pVM, PPDMUSBINS pUsbIns, PPPDMASYNCCOMPLETIONTEMPLATE ppTemplate, PFNPDMASYNCCOMPLETEUSB pfnCompleted, const char *pszDesc);
162
163/**
164 * Creates a async completion template for internally by the VMM.
165 *
166 * The template is used when creating new completion tasks.
167 *
168 * @returns VBox status code.
169 * @param pVM Pointer to the shared VM structure.
170 * @param ppTemplate Where to store the template pointer on success.
171 * @param pfnCompleted The completion callback routine.
172 * @param pvUser2 The 2nd user argument for the callback.
173 * @param pszDesc Description.
174 */
175VMMR3DECL(int) PDMR3AsyncCompletionTemplateCreateInternal(PVM pVM, PPPDMASYNCCOMPLETIONTEMPLATE ppTemplate, PFNPDMASYNCCOMPLETEINT pfnCompleted, void *pvUser2, const char *pszDesc);
176
177/**
178 * Destroys the specified async completion template.
179 *
180 * @returns VBox status codes:
181 * @retval VINF_SUCCESS on success.
182 * @retval VERR_PDM_ASYNC_TEMPLATE_BUSY if the template is still in use.
183 *
184 * @param pTemplate The template in question.
185 */
186VMMR3DECL(int) PDMR3AsyncCompletionTemplateDestroy(PPDMASYNCCOMPLETIONTEMPLATE pTemplate);
187
188/**
189 * Destroys all the specified async completion templates for the given device instance.
190 *
191 * @returns VBox status codes:
192 * @retval VINF_SUCCESS on success.
193 * @retval VERR_PDM_ASYNC_TEMPLATE_BUSY if one or more of the templates are still in use.
194 *
195 * @param pVM Pointer to the shared VM structure.
196 * @param pDevIns The device instance.
197 */
198VMMR3DECL(int) PDMR3AsyncCompletionTemplateDestroyDevice(PVM pVM, PPDMDEVINS pDevIns);
199
200/**
201 * Destroys all the specified async completion templates for the given driver instance.
202 *
203 * @returns VBox status codes:
204 * @retval VINF_SUCCESS on success.
205 * @retval VERR_PDM_ASYNC_TEMPLATE_BUSY if one or more of the templates are still in use.
206 *
207 * @param pVM Pointer to the shared VM structure.
208 * @param pDrvIns The driver instance.
209 */
210VMMR3DECL(int) PDMR3AsyncCompletionTemplateDestroyDriver(PVM pVM, PPDMDRVINS pDrvIns);
211
212/**
213 * Destroys all the specified async completion templates for the given USB device instance.
214 *
215 * @returns VBox status codes:
216 * @retval VINF_SUCCESS on success.
217 * @retval VERR_PDM_ASYNC_TEMPLATE_BUSY if one or more of the templates are still in use.
218 *
219 * @param pVM Pointer to the shared VM structure.
220 * @param pUsbIns The USB device instance.
221 */
222VMMR3DECL(int) PDMR3AsyncCompletionTemplateDestroyUsb(PVM pVM, PPDMUSBINS pUsbIns);
223
224/**
225 * Async completion task type
226 */
227typedef enum PDMASYNCCOMPLETIONTASKTYPE
228{
229 /** Socket. */
230 PDMASYNCCOMPLETIONTASKTYPE_SOCKET = 0,
231 /** Host OS specific. */
232 PDMASYNCCOMPLETIONTASKTYPE_HOST,
233 /** Number of supported backends. This has to be last entry! */
234 PDMASYNCCOMPLETIONTASKTYPE_SUPPORTED
235} PDMASYNCCOMPLETIONTASKTYPE;
236
237/**
238 * Get the backend name of a task type.
239 *
240 * @returns Name of the backend.
241 * @param enmTaskType The task type to get the backend name from.
242 */
243VMMR3DECL(const char *) PDMR3AsyncCompletionGetBackendName(PDMASYNCCOMPLETIONTASKTYPE enmTaskType);
244
245/**
246 * Creates a completion task.
247 *
248 * @returns VBox status code.
249 * @param ppTask Where to store the task handle on success.
250 * @param pTemplate The async completion template.
251 * @param enmType The type of the task.
252 * @param pvCtx The task specific context.
253 * @param pvUser The user argument for the callback.
254 */
255VMMR3DECL(int) PDMR3AsyncCompletionTaskCreate(PPPDMASYNCCOMPLETIONTASK ppTask, PPDMASYNCCOMPLETIONTEMPLATE pTemplate, PDMASYNCCOMPLETIONTASKTYPE enmType, void *pvCtx, void *pvUser);
256
257/**
258 * Submit an array of tasks for processing
259 * The tasks must have a type specific context.
260 *
261 * @returns VBox status code.
262 * @param apTasks Array of tasks which should be processed.
263 * @param cTasks Number of tasks in the array which should be processed.
264 */
265VMMR3DECL(int) PDMR3AsyncCompletionTaskSubmit(PPDMASYNCCOMPLETIONTASK apTasks[], unsigned cTasks);
266
267/**
268 * Sets the user argument of a completion task.
269 *
270 * @returns VBox status code.
271 * @param pTask The async completion task.
272 * @param pvUser The user argument for the callback.
273 */
274VMMR3DECL(int) PDMR3AsyncCompletionTaskSetUserArg(PPDMASYNCCOMPLETIONTASK pTask, void *pvUser);
275
276/**
277 * Suspends a async completion task.
278 *
279 * @returns VBox status codes:
280 * @retval VINF_SUCCESS on success.
281 * @retval VERR_PDM_ASYNC_COMPLETION_ALREADY_SUSPENDED if already suspended.
282 * @retval VERR_INVALID_HANDLE if pTask is invalid (asserts).
283 * @param pTask The async completion task.
284 */
285VMMR3DECL(int) PDMR3AsyncCompletionTaskSuspend(PPDMASYNCCOMPLETIONTASK pTask);
286
287/**
288 * Suspends a async completion task.
289 *
290 * @returns VBox status codes:
291 * @retval VINF_SUCCESS on success.
292 * @retval VERR_PDM_ASYNC_COMPLETION_NOT_SUSPENDED if not suspended.
293 * @retval VERR_INVALID_HANDLE if pTask is invalid (asserts).
294 * @param pTask The async completion task.
295 */
296VMMR3DECL(int) PDMR3AsyncCompletionTaskResume(PPDMASYNCCOMPLETIONTASK pTask);
297
298/**
299 * Cancels a async completion task.
300 * The task doesn't have to be suspended.
301 *
302 * @returns VBox status code
303 * @param pTask The Task to cancel.
304 */
305VMMR3DECL(int) PDMR3AsyncCompletionTaskCancel(PPDMASYNCCOMPLETIONTASK pTask);
306
307/**
308 * Destroys a async completion task.
309 *
310 * The task doesn't have to be suspended or anything.
311 *
312 * @returns VBox status codes:
313 * @retval VINF_SUCCESS on success.
314 * @retval VERR_INVALID_HANDLE if pTask is invalid but not NIL (asserts).
315 * @param pTask The async completion task.
316 */
317VMMR3DECL(int) PDMR3AsyncCompletionTaskDestroy(PPDMASYNCCOMPLETIONTASK pTask);
318
319/*
320 * Host specific wrapper functions for the above API
321 */
322#if defined(RT_OS_LINUX)
323
324struct iocb;
325
326/**
327 * Creates a completion task for an IO operation on Linux.
328 *
329 * The pvCtx callback argument will be pIoCB.
330 *
331 * @returns VBox status code.
332 * @param ppTask Where to store the task handle on success.
333 * @param pTemplate The async completion template.
334 * @param pIoCB The asynchronous I/O control block to wait for.
335 * @param pvUser The user argument for the callback.
336 */
337DECLINLINE(int) PDMR3AsyncCompletionCreateLnxIO(PPPDMASYNCCOMPLETIONTASK ppTask, PPDMASYNCCOMPLETIONTEMPLATE pTemplate, const struct iocb *pIoCB, void *pvUser)
338{
339 int rc = VINF_SUCCESS;
340 PPDMASYNCCOMPLETIONTASK pTask;
341
342 rc = PDMR3AsyncCompletionTaskCreate(&pTask, pTemplate, PDMASYNCCOMPLETIONTASKTYPE_HOST, (void *)pIoCB, pvUser);
343 if (RT_FAILURE(rc))
344 {
345 AssertMsgFailed(("Creating Linux task failed\n"));
346 return rc;
347 }
348
349 *ppTask = pTask;
350
351 return rc;
352}
353#endif /* RT_OS_LINUX */
354
355#if defined(RT_OS_SOLARIS) || defined(RT_OS_DARWIN) || defined(RT_OS_FREEBSD) || defined(RT_OS_LINUX)
356
357struct aiocb;
358
359/**
360 * Creates a completion task for an AIO operation on Unix like systems like Solaris, Darwin or FreeBSD.
361 * This method must be used too on Linux if the real asynchronous solution is not available.
362 *
363 * The pvCtx callback argument will be pAioCB.
364 *
365 * @returns VBox status code.
366 * @param ppTask Where to store the task handle on success.
367 * @param pTemplate The async completion template.
368 * @param pIoCB The asynchronous I/O control block to wait for.
369 * @param pvUser The user argument for the callback.
370 */
371DECLINLINE(int) PDMR3AsyncCompletionCreateUnxAIO(PPPDMASYNCCOMPLETIONTASK ppTask, PPDMASYNCCOMPLETIONTEMPLATE pTemplate, const struct aiocb *pAioCB, void *pvUser)
372{
373 int rc = VINF_SUCCESS;
374 PPDMASYNCCOMPLETIONTASK pTask;
375
376 rc = PDMR3AsyncCompletionTaskCreate(&pTask, pTemplate, PDMASYNCCOMPLETIONTASKTYPE_HOST, (void *)pAioCB, pvUser);
377 if (RT_FAILURE(rc))
378 {
379 AssertMsgFailed(("Creating AIO task failed\n"));
380 return rc;
381 }
382
383 *ppTask = pTask;
384
385 return rc;
386}
387#endif /* RT_OS_SOLARIS || RT_OS_DARWIN || RT_OS_FREEBSD || RT_OS_LINUX */
388
389#ifdef RT_OS_OS2
390/**
391 * Creates a completion task for an event semaphore on OS/2.
392 *
393 * The pvCtx callback argument will be hev.
394 *
395 * @returns VBox status code.
396 * @param ppTask Where to store the task handle on success.
397 * @param pTemplate The async completion template.
398 * @param hev The handle of the event semaphore to wait on.
399 * @param pvUser The user argument for the callback.
400 */
401DECLINLINE(int) PDMR3AsyncCompletionCreateOs2Event(PPPDMASYNCCOMPLETIONTASK ppTask, PPDMASYNCCOMPLETIONTEMPLATE pTemplate, unsigned long hev, void *pvUser)
402{
403 int rc = VINF_SUCCESS;
404 PPDMASYNCCOMPLETIONTASK pTask;
405
406 rc = PDMR3AsyncCompletionTaskCreate(&pTask, pTemplate, PDMASYNCCOMPLETIONTASKTYPE_HOST, (void *)&hev, pvUser);
407 if (RT_FAILURE(rc))
408 {
409 AssertMsgFailed(("Creating OS/2 task failed\n"));
410 return rc;
411 }
412
413 *ppTask = pTask;
414
415 return rc;
416}
417#endif /* RT_OS_OS2 */
418
419#ifdef RT_OS_WINDOWS
420/**
421 * Creates a completion task for an object on Windows.
422 *
423 * The pvCtx callback argument will be hObject.
424 *
425 * @returns VBox status code.
426 * @param ppTask Where to store the task handle on success.
427 * @param pTemplate The async completion template.
428 * @param hObject The object to wait for.
429 * @param pvUser The user argument for the callback.
430 */
431DECLINLINE(int) PDMR3AsyncCompletionCreateWinObject(PPPDMASYNCCOMPLETIONTASK ppTask, PPDMASYNCCOMPLETIONTEMPLATE pTemplate, void *hObject, void *pvUser)
432{
433 int rc = VINF_SUCCESS;
434 PPDMASYNCCOMPLETIONTASK pTask;
435
436 rc = PDMR3AsyncCompletionTaskCreate(&pTask, pTemplate, PDMASYNCCOMPLETIONTASKTYPE_HOST, (void *)hObject, pvUser);
437 if (RT_FAILURE(rc))
438 {
439 AssertMsgFailed(("Creating Windows task failed\n"));
440 return rc;
441 }
442
443 *ppTask = pTask;
444
445 return rc;
446}
447#endif /* RT_OS_WINDOWS */
448
449/**
450 * Socket completion context (pvCtx).
451 */
452typedef struct PDMASYNCCOMPLETIONSOCKET
453{
454 /** The socket. */
455 RTSOCKET Socket;
456 /** Readable. */
457 bool fReadable;
458 /** Writable. */
459 bool fWriteable;
460 /** Exceptions. */
461 bool fXcpt;
462} PDMASYNCCOMPLETIONSOCKET;
463/** Pointer to a socket completion context. */
464typedef PDMASYNCCOMPLETIONSOCKET *PPDMASYNCCOMPLETIONSOCKET;
465
466/**
467 * Creates a completion task for a socket.
468 *
469 * The pvCtx callback argument will be pointing to a PDMASYNCCOMPLETIONSOCKET structure.
470 *
471 * @returns VBox status code.
472 * @param ppTask Where to store the task handle on success.
473 * @param pTemplate The async completion template.
474 * @param Socket The socket.
475 * @param fReadable Whether to callback when the socket becomes readable.
476 * @param fWriteable Whether to callback when the socket becomes writable.
477 * @param fXcpt Whether to callback on exception.
478 * @param pvUser The user argument for the callback.
479 */
480DECLINLINE(int) PDMR3AsyncCompletionCreateSocket(PPPDMASYNCCOMPLETIONTASK ppTask, PPDMASYNCCOMPLETIONTEMPLATE pTemplate, RTSOCKET Socket, bool fReadable, bool fWriteable, bool fXcpt, void *pvUser)
481{
482 int rc = VINF_SUCCESS;
483 PPDMASYNCCOMPLETIONTASK pTask;
484 PDMASYNCCOMPLETIONSOCKET SocketContext;
485
486 SocketContext.Socket = Socket;
487 SocketContext.fReadable = fReadable;
488 SocketContext.fWriteable = fWriteable;
489 SocketContext.fXcpt = fXcpt;
490
491 rc = PDMR3AsyncCompletionTaskCreate(&pTask, pTemplate, PDMASYNCCOMPLETIONTASKTYPE_SOCKET, (void *)&SocketContext, pvUser);
492 if (RT_FAILURE(rc))
493 {
494 AssertMsgFailed(("Creating Socket task failed\n"));
495 return rc;
496 }
497
498 *ppTask = pTask;
499
500 return rc;
501}
502
503#if 0
504/**
505 * Modifies a socket completion task.
506 *
507 * @returns VBox status code.
508 * @retval VINF_SUCCESS on success.
509 * @retval VERR_NOT_SUPPORTED if the task isn't a socket task.
510 * @param pTemplate The async completion template.
511 * @param Socket The socket
512 * @param fReadable Whether to callback when the socket becomes readable.
513 * @param fWriteable Whether to callback when the socket becomes writable.
514 * @param fXcpt Whether to callback on exception.
515 */
516DECLINLINE(int) PDMR3AsyncCompletionModifySocket(PPDMASYNCCOMPLETIONTASK pTask, RTSOCKET Socket, bool fReadable, bool fWriteable, bool fXcpt)
517{
518 int rc = VINF_SUCCESS;
519 PDMASYNCCOMPLETIONSOCKET SocketContext;
520
521 SocketContext.Socket = Socket;
522 SocketContext.fReadable = fReadable;
523 SocketContext.fWriteable = fWriteable;
524 SocketContext.fXcpt = fXcpt;
525
526 rc = PDMR3AsyncCompletionTaskAssociate(pTask, &SocketContext);
527 if (RT_FAILURE(rc))
528 {
529 AssertMsgFailed(("Modifying Socket task failed\n"));
530 return rc;
531 }
532
533 return rc;
534}
535#endif
536
537/** @} */
538
539__END_DECLS
540
541#endif
542
543
544
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette