VirtualBox

Changeset 25640 in vbox


Ignore:
Timestamp:
Jan 4, 2010 4:44:23 PM (15 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
56342
Message:

iprt: Added RTSemEventMulti[Set|Add|Remove]Signaller.

Location:
trunk
Files:
7 edited

Legend:

Unmodified
Added
Removed
  • trunk/include/iprt/semaphore.h

    r25638 r25640  
    143143 * @param   hThread             A previously added thread.
    144144 */
    145 RTDECL(void) RTSemEventRemoverSignaller(RTSEMEVENT hEventSem, RTTHREAD hThread);
     145RTDECL(void) RTSemEventRemoveSignaller(RTSEMEVENT hEventSem, RTTHREAD hThread);
    146146
    147147/** @} */
     
    211211 */
    212212RTDECL(int)  RTSemEventMultiWaitNoResume(RTSEMEVENTMULTI EventMultiSem, unsigned cMillies);
     213
     214/**
     215 * Sets the signaller thread to one specific thread.
     216 *
     217 * This is only used for validating usage and deadlock detection.  When used
     218 * after calls to RTSemEventAddSignaller, the specified thread will be the only
     219 * signalling thread.
     220 *
     221 * @param   hEventMultiSem      The multiple release event semaphore.
     222 * @param   hThread             The thread that will signal it.  Pass
     223 *                              NIL_RTTHREAD to indicate that there is no
     224 *                              special signalling thread.
     225 */
     226RTDECL(void) RTSemEventMultiSetSignaller(RTSEMEVENTMULTI hEventMultiSem, RTTHREAD hThread);
     227
     228/**
     229 * To add more signalling threads.
     230 *
     231 * First call RTSemEventSetSignaller then add further threads with this.
     232 *
     233 * @param   hEventMultiSem      The multiple release event semaphore.
     234 * @param   hThread             The thread that will signal it. NIL_RTTHREAD is
     235 *                              not accepted.
     236 */
     237RTDECL(void) RTSemEventMultiAddSignaller(RTSEMEVENTMULTI hEventMultiSem, RTTHREAD hThread);
     238
     239/**
     240 * To remove a signalling thread.
     241 *
     242 * Reverts work done by RTSemEventAddSignaller and RTSemEventSetSignaller.
     243 *
     244 * @param   hEventMultiSem      The multiple release event semaphore.
     245 * @param   hThread             A previously added thread.
     246 */
     247RTDECL(void) RTSemEventMultiRemoveSignaller(RTSEMEVENTMULTI hEventMultiSem, RTTHREAD hThread);
    213248
    214249/** @} */
  • trunk/src/VBox/Runtime/r3/linux/semeventmulti-linux.cpp

    r22959 r25640  
    3131
    3232#include <features.h>
    33 #if __GLIBC_PREREQ(2,6) && !defined(IPRT_WITH_FUTEX_BASED_SEMS)
     33#if __GLIBC_PREREQ(2,6) && !defined(IPRT_WITH_FUTEX_BASED_SEMS) && !defined(DEBUG_bird)
    3434
    3535/*
     
    300300}
    301301
     302
     303RTDECL(void) RTSemEventMultiSetSignaller(RTSEMEVENTMULTI hEventMultiSem, RTTHREAD hThread)
     304{
     305    /** @todo implement RTSemEventMultiSetSignaller on OS/2 */
     306}
     307
     308
     309RTDECL(void) RTSemEventMultiAddSignaller(RTSEMEVENTMULTI hEventMultiSem, RTTHREAD hThread)
     310{
     311}
     312
     313
     314RTDECL(void) RTSemEventMultiRemoveSignaller(RTSEMEVENTMULTI hEventMultiSem, RTTHREAD hThread)
     315{
     316}
     317
    302318#endif /* glibc < 2.6 || IPRT_WITH_FUTEX_BASED_SEMS */
    303319
  • trunk/src/VBox/Runtime/r3/os2/sems-os2.cpp

    r25638 r25640  
    136136
    137137
    138 RTDECL(void) RTSemEventRemoverSignaller(RTSEMEVENT hEventSem, RTTHREAD hThread)
     138RTDECL(void) RTSemEventRemoveSignaller(RTSEMEVENT hEventSem, RTTHREAD hThread)
    139139{
    140140
     
    313313
    314314
    315 
     315RTDECL(void) RTSemEventMultiSetSignaller(RTSEMEVENTMULTI hEventMultiSem, RTTHREAD hThread)
     316{
     317    /** @todo implement RTSemEventMultiSetSignaller on OS/2 */
     318}
     319
     320
     321RTDECL(void) RTSemEventMultiAddSignaller(RTSEMEVENTMULTI hEventMultiSem, RTTHREAD hThread)
     322{
     323}
     324
     325
     326RTDECL(void) RTSemEventMultiRemoveSignaller(RTSEMEVENTMULTI hEventMultiSem, RTTHREAD hThread)
     327{
     328}
     329
  • trunk/src/VBox/Runtime/r3/posix/semeventmulti-posix.cpp

    r25636 r25640  
    3333*******************************************************************************/
    3434#include <iprt/semaphore.h>
     35#include "internal/iprt.h"
     36
     37#include <iprt/asm.h>
    3538#include <iprt/assert.h>
    36 #include <iprt/alloc.h>
    37 #include <iprt/asm.h>
    3839#include <iprt/err.h>
     40#include <iprt/lockvalidator.h>
     41#include <iprt/mem.h>
     42
     43#include "internal/strict.h"
    3944
    4045#include <errno.h>
     
    6166    /** Number of waiters. */
    6267    volatile uint32_t   cWaiters;
     68#ifdef RTSEMEVENTMULTI_STRICT
     69    /** Signallers. */
     70    RTLOCKVALRECSHRD    Signallers;
     71    /** Indicates that lock validation should be performed. */
     72    bool volatile       fEverHadSignallers;
     73#endif
    6374};
    6475
     
    7384/** @} */
    7485
    75 
    76 
    77 /**
    78  * Validate an event multi semaphore handle passed to one of the interface.
    79  *
    80  * @returns true if valid.
    81  * @returns false if invalid.
    82  * @param   pThis    Pointer to the event semaphore to validate.
    83  */
    84 inline bool rtsemEventMultiValid(struct RTSEMEVENTMULTIINTERNAL *pThis)
    85 {
    86     if ((uintptr_t)pThis < 0x10000)
    87         return false;
    88 
    89     uint32_t    u32 = pThis->u32State; /* this is volatile, so a explicit read like this is needed. */
    90     if (    u32 != EVENTMULTI_STATE_NOT_SIGNALED
    91         &&  u32 != EVENTMULTI_STATE_SIGNALED)
    92         return false;
    93 
    94     return true;
    95 }
    9686
    9787
     
    131121                        ASMAtomicXchgU32(&pThis->u32State, EVENTMULTI_STATE_NOT_SIGNALED);
    132122                        ASMAtomicXchgU32(&pThis->cWaiters, 0);
     123#ifdef RTSEMEVENTMULTI_STRICT
     124                        RTLockValidatorRecSharedInit(&pThis->Signallers,
     125                                                     NIL_RTLOCKVALIDATORCLASS, RTLOCKVALIDATOR_SUB_CLASS_ANY,
     126                                                     "RTSemEvent", pThis, true /*fSignaller*/);
     127                        pThis->fEverHadSignallers = false;
     128#endif
    133129
    134130                        *pEventMultiSem = pThis;
     
    159155     * Validate handle.
    160156     */
    161     if (!rtsemEventMultiValid(EventMultiSem))
    162     {
    163         AssertMsgFailed(("Invalid handle %p!\n", EventMultiSem));
    164         return VERR_INVALID_HANDLE;
    165     }
     157    struct RTSEMEVENTMULTIINTERNAL *pThis = EventMultiSem;
     158    if (pThis == NIL_RTSEMEVENTMULTI)
     159        return VINF_SUCCESS;
     160    AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
     161    uint32_t u32 = pThis->u32State;
     162    AssertReturn(u32 == EVENTMULTI_STATE_NOT_SIGNALED || u32 == EVENTMULTI_STATE_SIGNALED, VERR_INVALID_HANDLE);
    166163
    167164    /*
    168165     * Abort all waiters forcing them to return failure.
    169166     */
    170     struct RTSEMEVENTMULTIINTERNAL *pThis = EventMultiSem;
    171167    int rc;
    172168    for (int i = 30; i > 0; i--)
     
    205201     * Free the semaphore memory and be gone.
    206202     */
     203#ifdef RTSEMEVENTMULTI_STRICT
     204    RTLockValidatorRecSharedDelete(&pThis->Signallers);
     205#endif
    207206    RTMemFree(pThis);
    208207    return VINF_SUCCESS;
     
    215214     * Validate input.
    216215     */
    217     if (!rtsemEventMultiValid(EventMultiSem))
    218     {
    219         AssertMsgFailed(("Invalid handle %p!\n", EventMultiSem));
    220         return VERR_INVALID_HANDLE;
    221     }
     216    struct RTSEMEVENTMULTIINTERNAL *pThis = EventMultiSem;
     217    AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
     218    uint32_t u32 = pThis->u32State;
     219    AssertReturn(u32 == EVENTMULTI_STATE_NOT_SIGNALED || u32 == EVENTMULTI_STATE_SIGNALED, VERR_INVALID_HANDLE);
     220
     221#ifdef RTSEMEVENTMULTI_STRICT
     222    if (pThis->fEverHadSignallers)
     223    {
     224        int rc9 = RTLockValidatorRecSharedCheckSignaller(&pThis->Signallers, NIL_RTTHREAD);
     225        if (RT_FAILURE(rc9))
     226            return rc9;
     227    }
     228#endif
    222229
    223230    /*
    224231     * Lock the mutex semaphore.
    225232     */
    226     struct RTSEMEVENTMULTIINTERNAL *pThis = EventMultiSem;
    227233    int rc = pthread_mutex_lock(&pThis->Mutex);
    228234    if (rc)
     
    268274     * Validate input.
    269275     */
    270     if (!rtsemEventMultiValid(EventMultiSem))
    271     {
    272         AssertMsgFailed(("Invalid handle %p!\n", EventMultiSem));
    273         return VERR_INVALID_HANDLE;
    274     }
     276    struct RTSEMEVENTMULTIINTERNAL *pThis = EventMultiSem;
     277    AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
     278    uint32_t u32 = pThis->u32State;
     279    AssertReturn(u32 == EVENTMULTI_STATE_NOT_SIGNALED || u32 == EVENTMULTI_STATE_SIGNALED, VERR_INVALID_HANDLE);
    275280
    276281    /*
    277282     * Lock the mutex semaphore.
    278283     */
    279     struct RTSEMEVENTMULTIINTERNAL *pThis = EventMultiSem;
    280284    int rc = pthread_mutex_lock(&pThis->Mutex);
    281285    if (rc)
     
    310314static int rtSemEventMultiWait(RTSEMEVENTMULTI EventMultiSem, unsigned cMillies, bool fAutoResume)
    311315{
     316    PCRTLOCKVALSRCPOS pSrcPos = NULL;
     317
    312318    /*
    313319     * Validate input.
    314320     */
    315     if (!rtsemEventMultiValid(EventMultiSem))
    316     {
    317         AssertMsgFailed(("Invalid handle %p!\n", EventMultiSem));
    318         return VERR_INVALID_HANDLE;
    319     }
     321    struct RTSEMEVENTMULTIINTERNAL *pThis = EventMultiSem;
     322    AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
     323    uint32_t u32 = pThis->u32State;
     324    AssertReturn(u32 == EVENTMULTI_STATE_NOT_SIGNALED || u32 == EVENTMULTI_STATE_SIGNALED, VERR_INVALID_HANDLE);
    320325
    321326    /*
    322327     * Timed or indefinite wait?
    323328     */
    324     struct RTSEMEVENTMULTIINTERNAL *pThis = EventMultiSem;
    325329    if (cMillies == RT_INDEFINITE_WAIT)
    326330    {
     
    352356
    353357            /* wait */
     358#ifdef RTSEMEVENTMULTI_STRICT
     359            RTTHREAD hThreadSelf = RTThreadSelfAutoAdopt();
     360            if (pThis->fEverHadSignallers)
     361            {
     362                rc = RTLockValidatorRecSharedCheckBlocking(&pThis->Signallers, hThreadSelf, pSrcPos, false,
     363                                                           RTTHREADSTATE_EVENT_MULTI, true);
     364                if (RT_FAILURE(rc))
     365                {
     366                    ASMAtomicDecU32(&pThis->cWaiters);
     367                    pthread_mutex_unlock(&pThis->Mutex);
     368                    return rc;
     369                }
     370            }
     371#else
     372            RTTHREAD hThreadSelf = RTThreadSelf();
     373#endif
     374            RTThreadBlocking(hThreadSelf, RTTHREADSTATE_EVENT_MULTI, true);
    354375            rc = pthread_cond_wait(&pThis->Cond, &pThis->Mutex);
     376            RTThreadUnblocked(hThreadSelf, RTTHREADSTATE_EVENT_MULTI);
    355377            if (rc)
    356378            {
     
    396418
    397419        /* take mutex */
    398 #ifdef RT_OS_DARWIN
    399420        int rc = pthread_mutex_lock(&pThis->Mutex);
    400 #else
    401         int rc = pthread_mutex_timedlock(&pThis->Mutex, &ts);
    402 #endif
    403421        if (rc)
    404422        {
     
    425443            }
    426444
     445            /* we're done if the timeout is 0. */
     446            if (!cMillies)
     447            {
     448                ASMAtomicDecU32(&pThis->cWaiters);
     449                rc = pthread_mutex_unlock(&pThis->Mutex);
     450                return VERR_SEM_BUSY;
     451            }
     452
    427453            /* wait */
     454#ifdef RTSEMEVENTMULTI_STRICT
     455            RTTHREAD hThreadSelf = RTThreadSelfAutoAdopt();
     456            if (pThis->fEverHadSignallers)
     457            {
     458                rc = RTLockValidatorRecSharedCheckBlocking(&pThis->Signallers, hThreadSelf, pSrcPos, false,
     459                                                           RTTHREADSTATE_EVENT_MULTI, true);
     460                if (RT_FAILURE(rc))
     461                {
     462                    ASMAtomicDecU32(&pThis->cWaiters);
     463                    pthread_mutex_unlock(&pThis->Mutex);
     464                    return rc;
     465                }
     466            }
     467#else
     468            RTTHREAD hThreadSelf = RTThreadSelf();
     469#endif
     470            RTThreadBlocking(hThreadSelf, RTTHREADSTATE_EVENT_MULTI, true);
    428471            rc = pthread_cond_timedwait(&pThis->Cond, &pThis->Mutex, &ts);
     472            RTThreadUnblocked(hThreadSelf, RTTHREADSTATE_EVENT_MULTI);
    429473            if (rc && (rc != EINTR || !fAutoResume)) /* according to SuS this function shall not return EINTR, but linux man page says differently. */
    430474            {
     
    453497}
    454498
     499
     500RTDECL(void) RTSemEventMultiSetSignaller(RTSEMEVENTMULTI hEventMultiSem, RTTHREAD hThread)
     501{
     502#ifdef RTSEMEVENTMULTI_STRICT
     503    struct RTSEMEVENTMULTIINTERNAL *pThis = hEventMultiSem;
     504    AssertPtrReturnVoid(pThis);
     505    uint32_t u32 = pThis->u32State;
     506    AssertReturnVoid(u32 == EVENTMULTI_STATE_NOT_SIGNALED || u32 == EVENTMULTI_STATE_SIGNALED);
     507
     508    ASMAtomicWriteBool(&pThis->fEverHadSignallers, true);
     509    RTLockValidatorRecSharedResetOwner(&pThis->Signallers, hThread, NULL);
     510#endif
     511}
     512
     513
     514RTDECL(void) RTSemEventMultiAddSignaller(RTSEMEVENTMULTI hEventMultiSem, RTTHREAD hThread)
     515{
     516#ifdef RTSEMEVENTMULTI_STRICT
     517    struct RTSEMEVENTMULTIINTERNAL *pThis = hEventMultiSem;
     518    AssertPtrReturnVoid(pThis);
     519    uint32_t u32 = pThis->u32State;
     520    AssertReturnVoid(u32 == EVENTMULTI_STATE_NOT_SIGNALED || u32 == EVENTMULTI_STATE_SIGNALED);
     521
     522    ASMAtomicWriteBool(&pThis->fEverHadSignallers, true);
     523    RTLockValidatorRecSharedAddOwner(&pThis->Signallers, hThread, NULL);
     524#endif
     525}
     526
     527
     528RTDECL(void) RTSemEventMultiRemoveSignaller(RTSEMEVENTMULTI hEventMultiSem, RTTHREAD hThread)
     529{
     530#ifdef RTSEMEVENTMULTI_STRICT
     531    struct RTSEMEVENTMULTIINTERNAL *pThis = hEventMultiSem;
     532    AssertPtrReturnVoid(pThis);
     533    uint32_t u32 = pThis->u32State;
     534    AssertReturnVoid(u32 == EVENTMULTI_STATE_NOT_SIGNALED || u32 == EVENTMULTI_STATE_SIGNALED);
     535
     536    RTLockValidatorRecSharedRemoveOwner(&pThis->Signallers, hThread);
     537#endif
     538}
     539
  • trunk/src/VBox/Runtime/r3/win/semevent-win.cpp

    r25638 r25640  
    137137
    138138
    139 RTDECL(void) RTSemEventRemoverSignaller(RTSEMEVENT hEventSem, RTTHREAD hThread)
     139RTDECL(void) RTSemEventRemoveSignaller(RTSEMEVENT hEventSem, RTTHREAD hThread)
    140140{
    141141
  • trunk/src/VBox/Runtime/r3/win/semeventmulti-win.cpp

    r25381 r25640  
    132132}
    133133
     134
     135RTDECL(void) RTSemEventMultiSetSignaller(RTSEMEVENTMULTI hEventMultiSem, RTTHREAD hThread)
     136{
     137    /** @todo implement RTSemEventMultiSetSignaller on Windows */
     138}
     139
     140
     141RTDECL(void) RTSemEventMultiAddSignaller(RTSEMEVENTMULTI hEventMultiSem, RTTHREAD hThread)
     142{
     143}
     144
     145
     146RTDECL(void) RTSemEventMultiRemoveSignaller(RTSEMEVENTMULTI hEventMultiSem, RTTHREAD hThread)
     147{
     148}
     149
  • trunk/src/VBox/Runtime/testcase/tstRTLockValidator.cpp

    r25638 r25640  
    630630
    631631
     632static DECLCALLBACK(int) test7Thread(RTTHREAD ThreadSelf, void *pvUser)
     633{
     634    uintptr_t       i     = (uintptr_t)pvUser;
     635    PRTCRITSECT     pMine = &g_aCritSects[i];
     636    PRTCRITSECT     pNext = &g_aCritSects[(i + 1) % g_cThreads];
     637
     638    RTTEST_CHECK_RC_RET(g_hTest, RTCritSectEnter(pMine), VINF_SUCCESS, rcCheck);
     639    if (i & 1)
     640        RTTEST_CHECK_RC(g_hTest, RTCritSectEnter(pMine), VINF_SUCCESS);
     641    if (testWaitForCritSectToBeOwned(pNext))
     642    {
     643        int rc;
     644        if (i != g_iDeadlockThread)
     645        {
     646            RTTEST_CHECK_RC(g_hTest, rc = RTCritSectEnter(pNext), VINF_SUCCESS);
     647            RTTEST_CHECK(g_hTest, RTThreadGetState(RTThreadSelf()) == RTTHREADSTATE_RUNNING);
     648            if (RT_SUCCESS(rc))
     649                RTTEST_CHECK_RC(g_hTest, rc = RTCritSectLeave(pNext), VINF_SUCCESS);
     650        }
     651        else
     652        {
     653            RTTEST_CHECK_RC_OK(g_hTest, rc = testWaitForAllOtherThreadsToSleep(RTTHREADSTATE_CRITSECT, 1));
     654            if (RT_SUCCESS(rc))
     655            {
     656                RTSemEventMultiSetSignaller(g_hSemEvtMulti, g_ahThreads[0]);
     657                for (uint32_t iThread = 1; iThread < g_cThreads; iThread++)
     658                    RTSemEventMultiAddSignaller(g_hSemEvtMulti, g_ahThreads[iThread]);
     659                RTTEST_CHECK(g_hTest, RTThreadGetState(RTThreadSelf()) == RTTHREADSTATE_RUNNING);
     660                RTTEST_CHECK_RC(g_hTest, RTSemEventMultiReset(g_hSemEvtMulti), VINF_SUCCESS);
     661                RTTEST_CHECK_RC(g_hTest, RTSemEventMultiWait(g_hSemEvtMulti, 10*1000), VERR_SEM_LV_DEADLOCK);
     662                RTTEST_CHECK(g_hTest, RTThreadGetState(RTThreadSelf()) == RTTHREADSTATE_RUNNING);
     663                RTTEST_CHECK_RC(g_hTest, RTSemEventMultiSignal(g_hSemEvtMulti), VINF_SUCCESS);
     664                RTTEST_CHECK(g_hTest, RTThreadGetState(RTThreadSelf()) == RTTHREADSTATE_RUNNING);
     665                RTTEST_CHECK_RC(g_hTest, RTSemEventMultiWait(g_hSemEvtMulti, 10*1000), VINF_SUCCESS);
     666                RTTEST_CHECK(g_hTest, RTThreadGetState(RTThreadSelf()) == RTTHREADSTATE_RUNNING);
     667                RTSemEventMultiSetSignaller(g_hSemEvtMulti, NIL_RTTHREAD);
     668            }
     669        }
     670        RTTEST_CHECK(g_hTest, RTThreadGetState(RTThreadSelf()) == RTTHREADSTATE_RUNNING);
     671    }
     672    if (i & 1)
     673        RTTEST_CHECK_RC(g_hTest, RTCritSectLeave(pMine), VINF_SUCCESS);
     674    RTTEST_CHECK_RC(g_hTest, RTCritSectLeave(pMine), VINF_SUCCESS);
     675    return VINF_SUCCESS;
     676}
     677
     678
     679static void test7(uint32_t cThreads, uint32_t cPasses)
     680{
     681    testIt(cThreads, cPasses, 0, test7Thread, "event multi");
     682}
     683
    632684static bool testIsLockValidationCompiledIn(void)
    633685{
     
    669721    RTTEST_CHECK_RET(g_hTest, RT_FAILURE_NP(rc), false);
    670722    RTTEST_CHECK_RC_OK_RET(g_hTest, RTSemEventDestroy(hSemEvt), false);
     723
     724    RTSEMEVENTMULTI hSemEvtMulti;
     725    RTTEST_CHECK_RC_OK_RET(g_hTest, RTSemEventMultiCreate(&hSemEvtMulti), false);
     726    RTSemEventMultiSetSignaller(hSemEvtMulti, RTThreadSelf());
     727    RTSemEventMultiSetSignaller(hSemEvtMulti, NIL_RTTHREAD);
     728    rc = RTSemEventMultiSignal(hSemEvtMulti);
     729    if (rc != VERR_SEM_LV_NOT_SIGNALLER)
     730        fRet = false;
     731    RTTEST_CHECK_RET(g_hTest, RT_FAILURE_NP(rc), false);
     732    RTTEST_CHECK_RC_OK_RET(g_hTest, RTSemEventMultiDestroy(hSemEvtMulti), false);
    671733
    672734    return fRet;
     
    703765    test6(3, 1);
    704766#endif
     767    test7(3, 1);
    705768
    706769    /*
     
    708771     */
    709772    RTLockValidatorSetQuiet(true);
     773#if 1
    710774    test1( 2, 256);                     /* 256 * 4ms = 1s (approx); 4ms == fudge factor */
    711775    test1( 3, 256);
     
    715779    test1(30, 256);
    716780
    717 #if 1
    718781    test2( 1, 256);
    719782    test2( 2, 256);
     
    738801    test5(15, 256);
    739802    test5(30, 256);
    740 #endif
    741803
    742804    test6( 2, 256);
     
    746808    test6(15, 256);
    747809    test6(30, 256);
     810#endif
     811
     812#if 1
     813    test7( 2, 256);
     814    test7( 3, 256);
     815    test7( 7, 256);
     816    test7(10, 256);
     817    test7(15, 256);
     818    test7(30, 256);
     819#endif
    748820
    749821    return RTTestSummaryAndDestroy(g_hTest);
Note: See TracChangeset for help on using the changeset viewer.

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