Ignore:
Timestamp:
Oct 31, 2009, 2:00:20 AM (16 years ago)
Author:
Dmitry A. Kuminov
Message:

3rdparty: os2/xsystray: Use shared memory pool instead of TLS for structures sent to the system tray server by the client-side API. The memory pool is big enough to hold ~64 simultaneous requests to the server (e.g. 64 parallel threads). This also fixes a potential bug when not all threads could re-give their per-thread memory blocks to the server process after it is stopped and restarted.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/3rdparty/os2/xsystray/xsystray_api.c

    r270 r272  
    1717#define INCL_DOSPROCESS
    1818#define INCL_WINWINDOWMGR
     19
    1920#define INCL_WINATOM
    2021#define INCL_WINPOINTERS
     
    2627#include <string.h>
    2728#include <sys/builtin.h>        // atomics
    28 #include <InnotekLIBC/thread.h> // TLS
    2929
    3030static HWND G_hwndSysTray = NULLHANDLE;
    31 static int G_itlsSysTrayCtlData = -1;
    32 
    33 static HWND FindSysTrayWindow()
     31            // window handle of the system tray server
     32
     33static PVOID G_pvMemoryPool = NULL;
     34             // memory pool for SYSTRAYCTLDATA structs used by WM_XST_CONTROL
     35             // messages. Note that once allocated, this memory is never freed:
     36             // it is intentional since the memory is assumed to be always in
     37             // need and that the system will free it when the application
     38             // terminates
     39
     40#define MEMORYPOOL_SIZE 65536
     41        // taking SYSTRAYCTLDATA size into account, this is enough for at least
     42        // 64 threads sending WM_XST_CONTROL simultaneously, which sounds sane
     43
     44// @todo to be on the safe side with casting in __atomic_cmpxchg32() we need
     45// compile-time assertions like this:
     46// AssertCompile(sizeof(uint32_t) == sizeof(HWND));
     47// AssertCompile(sizeof(uint32_t) == sizeof(PVOID));
     48
     49static HWND FindSysTrayServerWindow()
    3450{
    3551    char buf[sizeof(WNDCLASS_WIDGET_XSYSTRAY_SERVER) + 1];
     
    6278        {
    6379            bTriedFind = TRUE;
    64             HWND hwnd = FindSysTrayWindow();
     80            HWND hwnd = FindSysTrayWindow();
    6581            __atomic_cmpxchg32((uint32_t *)&G_hwndSysTray, hwnd, NULLHANDLE);
    6682            if (G_hwndSysTray == NULLHANDLE)
     
    7288            arc = ERROR_INVALID_HANDLE;
    7389            if (WinQueryWindowProcess(G_hwndSysTray, &pid, &tid))
    74                 arc = DosGiveSharedMem(__libc_TLSGet(G_itlsSysTrayCtlData),
     90                arc = DosGiveSharedMem(,
    7591                                       pid, PAG_READ | PAG_WRITE);
    7692            if (arc != NO_ERROR)
     
    100116}
    101117
    102 // This function returns a per-thread SYSTRAYCTLDATA pointer. We communicate
    103 // to the server thread using WinSendMsg() which allows us to reuse a single
    104 // memory block for all calls (WinSendMsg() doesn't return until the server is
    105 // done with processing the message).
    106 static PSYSTRAYCTLDATA GetSysTrayCtlDataPtr()
     118// This function allocates a SYSTRAYCTLDATA struct in the pool of shared memory.
     119// If there is no free space in the pool, it returns NULL. The allocated memory
     120// must be freed by FreeSysTrayCtlDataPtr() when not needed.
     121static PSYSTRAYCTLDATA AllocSysTrayCtlDataPtr()
    107122{
    108123    APIRET arc;
    109 
    110     // allocate a thread local storage entry if not done so
    111     if (G_itlsSysTrayCtlData == -1)
    112     {
    113         // @todo does XWorkplace have its own TLS? Or is it built with GCC? Not?
    114         // Use DosAllocThreadLocalMemory() directly then (though it's not nice
    115         // due to the too limited amount of memory space in that area)
    116         int itls = __libc_TLSAlloc();
    117         if (!__atomic_cmpxchg32(&G_itlsSysTrayCtlData, itls, -1))
     124    PVOID pvPool;
     125    PSYSTRAYCTLDATA pData;
     126
     127    if (!G_pvMemoryPool)
     128    {
     129        // Note: we don't PAG_COMMIT, DosSubAllocMem will do so when needed
     130        arc = DosAllocSharedMem((PVOID)&pvPool, NULL, MEMORYPOOL_SIZE,
     131                                PAG_READ | PAG_WRITE | OBJ_GIVEABLE);
     132        if (arc == NO_ERROR)
     133            arc = DosSubSetMem(pvPool,
     134                               DOSSUB_INIT | DOSSUB_SPARSE_OBJ,
     135                               MEMORYPOOL_SIZE);
     136        if (!__atomic_cmpxchg32((uint32_t *)&G_pvMemoryPool,
     137                                (uint32_t)pvPool, (uint32_t)NULL))
    118138        {
    119139            // another thread has already got an entry, discard our try
    120             if (itls != -1)
    121                 __libc_TLSFree(itls);
     140            if ()
     141                );
    122142        }
    123 
    124         if (G_itlsSysTrayCtlData == -1)
    125             return NULL;
    126     }
    127 
    128     // allocate a SYSTRAYCTLDATA struct for this thread if not done so
    129     PSYSTRAYCTLDATA pData = __libc_TLSGet(G_itlsSysTrayCtlData);
    130     if (!pData)
    131     {
    132         arc = DosAllocSharedMem((PVOID)&pData, NULL, sizeof(SYSTRAYCTLDATA),
    133                                 PAG_COMMIT | PAG_READ | PAG_WRITE | OBJ_GIVEABLE);
    134         if (arc != NO_ERROR)
    135             return NULL;
    136 
    137         __libc_TLSSet(G_itlsSysTrayCtlData, pData);
    138 
    139         // note that we don't ever free the allocated block since our API doesn't
    140         // have a concept of initialization/termination and therefore it's fine
    141         // if the memory stays allocated until application termination
    142     }
     143        else
     144        {
     145            // we could fail to allocate while being the first... give up
     146            if (arc != NO_ERROR)
     147                return NULL;
     148        }
     149    }
     150
     151    arc = DosSubAllocMem(G_pvMemoryPool, (PVOID)&pData, sizeof(SYSTRAYCTLDATA));
     152    if (arc != NO_ERROR)
     153        return NULL;
    143154
    144155    return pData;
     156
     157
     158
     159
     160
    145161}
    146162
     
    166182{
    167183    BOOL brc;
    168     PSYSTRAYCTLDATA pData = GetSysTrayCtlDataPtr();
     184    PSYSTRAYCTLDATA pData = SysTrayCtlDataPtr();
    169185    if (!pData)
    170186        return FALSE;
     
    184200    }
    185201
     202
     203
    186204    return brc;
    187205}
     
    224242    BOOL brc;
    225243    PPIB ppib;
    226     PSYSTRAYCTLDATA pData = GetSysTrayCtlDataPtr();
     244    PSYSTRAYCTLDATA pData = SysTrayCtlDataPtr();
    227245    if (!pData)
    228246        return FALSE;
     
    230248    // give all processes temporary access to hIcon
    231249    brc = WinSetPointerOwner(hIcon, 0, FALSE);
    232     if (!brc)
    233         return FALSE;
    234 
    235     pData->ulCommand = SYSTRAYCMD_ADDICON;
    236     pData->hwndSender = hwnd;
    237     pData->u.icon.ulId = ulId;
    238     pData->u.icon.hIcon = hIcon;
    239     pData->u.icon.ulMsgId = ulMsgId;
    240 
    241     brc = SendSysTrayCtlMsg(pData);
    242 
    243     // revoke temporary access to hIcon
    244     DosGetInfoBlocks(NULL, &ppib);
    245     WinSetPointerOwner(hIcon, ppib->pib_ulpid, TRUE);
     250    if (brc)
     251    {
     252        pData->ulCommand = SYSTRAYCMD_ADDICON;
     253        pData->hwndSender = hwnd;
     254        pData->u.icon.ulId = ulId;
     255        pData->u.icon.hIcon = hIcon;
     256        pData->u.icon.ulMsgId = ulMsgId;
     257
     258        brc = SendSysTrayCtlMsg(pData);
     259
     260        // revoke temporary access to hIcon
     261        DosGetInfoBlocks(NULL, &ppib);
     262        WinSetPointerOwner(hIcon, ppib->pib_ulpid, TRUE);
     263    }
     264
     265    FreeSysTrayCtlDataPtr(pData);
    246266
    247267    return brc;
     
    260280                          ULONG ulId)   // in: icon ID to remove
    261281{
    262     PSYSTRAYCTLDATA pData = GetSysTrayCtlDataPtr();
     282    BOOL brc;
     283    PSYSTRAYCTLDATA pData = AllocSysTrayCtlDataPtr();
    263284    if (!pData)
    264285        return FALSE;
     
    268289    pData->u.icon.ulId = ulId;
    269290
    270     return SendSysTrayCtlMsg(pData);
     291    brc = SendSysTrayCtlMsg(pData);
     292
     293    FreeSysTrayCtlDataPtr(pData);
     294
     295    return brc;
    271296}
    272297
     
    292317                              PSZ pszText)  // in: tooltip text
    293318{
    294     PSYSTRAYCTLDATA pData = GetSysTrayCtlDataPtr();
     319    BOOL brc;
     320    PSYSTRAYCTLDATA pData = AllocSysTrayCtlDataPtr();
    295321    if (!pData)
    296322        return FALSE;
     
    310336    }
    311337
    312     return SendSysTrayCtlMsg(pData);
     338    brc = SendSysTrayCtlMsg(pData);
     339
     340    FreeSysTrayCtlDataPtr(pData);
     341
     342    return brc;
    313343}
    314344
Note: See TracChangeset for help on using the changeset viewer.