diff options
author | Dave Parks <davep@lindenlab.com> | 2010-03-20 16:59:41 -0500 |
---|---|---|
committer | Dave Parks <davep@lindenlab.com> | 2010-03-20 16:59:41 -0500 |
commit | 8424ceb20f7baa6d5cf980d2b9ae92121d1dcb20 (patch) | |
tree | eb691b2e04d91d0f994f1fc04acd066e4d474384 /indra/llcommon | |
parent | 433996c2014d2f5ff5037d1fbb8bb5edbe818e1f (diff) | |
parent | 06e3d288e40e46204d84aed9c548a6ca529e78d8 (diff) |
merge
Diffstat (limited to 'indra/llcommon')
-rw-r--r-- | indra/llcommon/llassettype.cpp | 2 | ||||
-rw-r--r-- | indra/llcommon/llassettype.h | 7 | ||||
-rw-r--r-- | indra/llcommon/lldarray.h | 2 | ||||
-rw-r--r-- | indra/llcommon/llfoldertype.cpp | 3 | ||||
-rw-r--r-- | indra/llcommon/llfoldertype.h | 6 | ||||
-rw-r--r-- | indra/llcommon/llthread.cpp | 46 | ||||
-rw-r--r-- | indra/llcommon/llthread.h | 548 | ||||
-rw-r--r-- | indra/llcommon/stdenums.h | 3 |
8 files changed, 346 insertions, 271 deletions
diff --git a/indra/llcommon/llassettype.cpp b/indra/llcommon/llassettype.cpp index 6d5b12d840..3ea742957e 100644 --- a/indra/llcommon/llassettype.cpp +++ b/indra/llcommon/llassettype.cpp @@ -94,6 +94,8 @@ LLAssetDictionary::LLAssetDictionary() addEntry(LLAssetType::AT_LINK, new AssetEntry("LINK", "link", "symbolic link", FALSE)); addEntry(LLAssetType::AT_LINK_FOLDER, new AssetEntry("FOLDER_LINK", "link_f", "symbolic folder link", FALSE)); + addEntry(LLAssetType::AT_MESH, new AssetEntry("MESH", "mesh", "mesh", FALSE)); + addEntry(LLAssetType::AT_NONE, new AssetEntry("NONE", "-1", NULL, FALSE)); }; diff --git a/indra/llcommon/llassettype.h b/indra/llcommon/llassettype.h index c7bbc2e74a..3304258000 100644 --- a/indra/llcommon/llassettype.h +++ b/indra/llcommon/llassettype.h @@ -114,8 +114,11 @@ public: AT_LINK_FOLDER = 25, // Inventory folder link - - AT_COUNT = 26, + + AT_MESH = 49, + // Mesh data in our proprietary SLM format + + AT_COUNT = 50, // +*********************************************************+ // | TO ADD AN ELEMENT TO THIS ENUM: | diff --git a/indra/llcommon/lldarray.h b/indra/llcommon/lldarray.h index 0e56a11d53..af647c7e7a 100644 --- a/indra/llcommon/lldarray.h +++ b/indra/llcommon/lldarray.h @@ -202,7 +202,7 @@ public: { U32 n = mVector.size(); mIndexMap[k] = n; - mVector.resize(n+1); + mVector.push_back(Type()); llassert(mVector.size() == mIndexMap.size()); return mVector[n]; } diff --git a/indra/llcommon/llfoldertype.cpp b/indra/llcommon/llfoldertype.cpp index 2610fe9e6a..16ae4cddde 100644 --- a/indra/llcommon/llfoldertype.cpp +++ b/indra/llcommon/llfoldertype.cpp @@ -95,6 +95,9 @@ LLFolderDictionary::LLFolderDictionary() addEntry(LLFolderType::FT_CURRENT_OUTFIT, new FolderEntry("current", TRUE)); addEntry(LLFolderType::FT_OUTFIT, new FolderEntry("outfit", FALSE)); addEntry(LLFolderType::FT_MY_OUTFITS, new FolderEntry("my_otfts", TRUE)); + + addEntry(LLFolderType::FT_MESH, new FolderEntry("mesh", TRUE)); + addEntry(LLFolderType::FT_INBOX, new FolderEntry("inbox", TRUE)); addEntry(LLFolderType::FT_NONE, new FolderEntry("-1", FALSE)); diff --git a/indra/llcommon/llfoldertype.h b/indra/llcommon/llfoldertype.h index 7aa77f7f7e..409112a04e 100644 --- a/indra/llcommon/llfoldertype.h +++ b/indra/llcommon/llfoldertype.h @@ -86,9 +86,11 @@ public: FT_OUTFIT = 47, FT_MY_OUTFITS = 48, - FT_INBOX = 49, + FT_MESH = 49, - FT_COUNT = 50, + FT_INBOX = 50, + + FT_COUNT = 51, FT_NONE = -1 }; diff --git a/indra/llcommon/llthread.cpp b/indra/llcommon/llthread.cpp index 37370e44e7..0385569a02 100644 --- a/indra/llcommon/llthread.cpp +++ b/indra/llcommon/llthread.cpp @@ -62,6 +62,12 @@ // //---------------------------------------------------------------------------- +#if !LL_DARWIN +U32 ll_thread_local sThreadID = 0; +#endif + +U32 LLThread::sIDIter = 0; + // // Handed to the APR thread creation function // @@ -72,10 +78,14 @@ void *APR_THREAD_FUNC LLThread::staticRun(apr_thread_t *apr_threadp, void *datap // Set thread state to running threadp->mStatus = RUNNING; +#if !LL_DARWIN + sThreadID = threadp->mID; +#endif + // Run the user supplied function threadp->run(); - llinfos << "LLThread::staticRun() Exiting: " << threadp->mName << llendl; + //llinfos << "LLThread::staticRun() Exiting: " << threadp->mName << llendl; // We're done with the run function, this thread is done executing now. threadp->mStatus = STOPPED; @@ -90,6 +100,8 @@ LLThread::LLThread(const std::string& name, apr_pool_t *poolp) : mAPRThreadp(NULL), mStatus(STOPPED) { + mID = ++sIDIter; + // Thread creation probably CAN be paranoid about APR being initialized, if necessary if (poolp) { @@ -273,7 +285,7 @@ void LLThread::wakeLocked() //============================================================================ LLMutex::LLMutex(apr_pool_t *poolp) : - mAPRMutexp(NULL) + mAPRMutexp(NULL), mCount(0), mLockingThread(NO_THREAD) { //if (poolp) //{ @@ -305,7 +317,18 @@ LLMutex::~LLMutex() void LLMutex::lock() { +#if LL_DARWIN + if (mLockingThread == LLThread::currentID()) +#else + if (mLockingThread == sThreadID) +#endif + { //redundant lock + mCount++; + return; + } + apr_thread_mutex_lock(mAPRMutexp); + #if MUTEX_DEBUG // Have to have the lock before we can access the debug info U32 id = LLThread::currentID(); @@ -313,10 +336,22 @@ void LLMutex::lock() llerrs << "Already locked in Thread: " << id << llendl; mIsLocked[id] = TRUE; #endif + +#if LL_DARWIN + mLockingThread = LLThread::currentID(); +#else + mLockingThread = sThreadID; +#endif } void LLMutex::unlock() { + if (mCount > 0) + { //not the root unlock + mCount--; + return; + } + #if MUTEX_DEBUG // Access the debug info while we have the lock U32 id = LLThread::currentID(); @@ -324,6 +359,8 @@ void LLMutex::unlock() llerrs << "Not locked in Thread: " << id << llendl; mIsLocked[id] = FALSE; #endif + + mLockingThread = NO_THREAD; apr_thread_mutex_unlock(mAPRMutexp); } @@ -341,6 +378,11 @@ bool LLMutex::isLocked() } } +U32 LLMutex::lockingThread() const +{ + return mLockingThread; +} + //============================================================================ LLCondition::LLCondition(apr_pool_t *poolp) : diff --git a/indra/llcommon/llthread.h b/indra/llcommon/llthread.h index adef1a9192..5d5ecd62fc 100644 --- a/indra/llcommon/llthread.h +++ b/indra/llcommon/llthread.h @@ -1,263 +1,285 @@ -/** - * @file llthread.h - * @brief Base classes for thread, mutex and condition handling. - * - * $LicenseInfo:firstyear=2004&license=viewergpl$ - * - * Copyright (c) 2004-2009, Linden Research, Inc. - * - * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 - * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception - * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. - * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. - * $/LicenseInfo$ - */ - -#ifndef LL_LLTHREAD_H -#define LL_LLTHREAD_H - -#include "llapp.h" -#include "llapr.h" -#include "apr_thread_cond.h" - -class LLThread; -class LLMutex; -class LLCondition; - -class LL_COMMON_API LLThread -{ -public: - typedef enum e_thread_status - { - STOPPED = 0, // The thread is not running. Not started, or has exited its run function - RUNNING = 1, // The thread is currently running - QUITTING= 2 // Someone wants this thread to quit - } EThreadStatus; - - LLThread(const std::string& name, apr_pool_t *poolp = NULL); - virtual ~LLThread(); // Warning! You almost NEVER want to destroy a thread unless it's in the STOPPED state. - virtual void shutdown(); // stops the thread - - bool isQuitting() const { return (QUITTING == mStatus); } - bool isStopped() const { return (STOPPED == mStatus); } - - static U32 currentID(); // Return ID of current thread - static void yield(); // Static because it can be called by the main thread, which doesn't have an LLThread data structure. - -public: - // PAUSE / RESUME functionality. See source code for important usage notes. - // Called from MAIN THREAD. - void pause(); - void unpause(); - bool isPaused() { return isStopped() || mPaused == TRUE; } - - // Cause the thread to wake up and check its condition - void wake(); - - // Same as above, but to be used when the condition is already locked. - void wakeLocked(); - - // Called from run() (CHILD THREAD). Pause the thread if requested until unpaused. - void checkPause(); - - // this kicks off the apr thread - void start(void); - - apr_pool_t *getAPRPool() { return mAPRPoolp; } - LLVolatileAPRPool* getLocalAPRFilePool() { return mLocalAPRFilePoolp ; } - -private: - BOOL mPaused; - - // static function passed to APR thread creation routine - static void *APR_THREAD_FUNC staticRun(apr_thread_t *apr_threadp, void *datap); - -protected: - std::string mName; - LLCondition* mRunCondition; - - apr_thread_t *mAPRThreadp; - apr_pool_t *mAPRPoolp; - BOOL mIsLocalPool; - EThreadStatus mStatus; - - //a local apr_pool for APRFile operations in this thread. If it exists, LLAPRFile::sAPRFilePoolp should not be used. - //Note: this pool is used by APRFile ONLY, do NOT use it for any other purposes. - // otherwise it will cause severe memory leaking!!! --bao - LLVolatileAPRPool *mLocalAPRFilePoolp ; - - void setQuitting(); - - // virtual function overridden by subclass -- this will be called when the thread runs - virtual void run(void) = 0; - - // virtual predicate function -- returns true if the thread should wake up, false if it should sleep. - virtual bool runCondition(void); - - // Lock/Unlock Run Condition -- use around modification of any variable used in runCondition() - inline void lockData(); - inline void unlockData(); - - // This is the predicate that decides whether the thread should sleep. - // It should only be called with mRunCondition locked, since the virtual runCondition() function may need to access - // data structures that are thread-unsafe. - bool shouldSleep(void) { return (mStatus == RUNNING) && (isPaused() || (!runCondition())); } - - // To avoid spurious signals (and the associated context switches) when the condition may or may not have changed, you can do the following: - // mRunCondition->lock(); - // if(!shouldSleep()) - // mRunCondition->signal(); - // mRunCondition->unlock(); -}; - -//============================================================================ - -#define MUTEX_DEBUG (LL_DEBUG || LL_RELEASE_WITH_DEBUG_INFO) - -class LL_COMMON_API LLMutex -{ -public: - LLMutex(apr_pool_t *apr_poolp); // NULL pool constructs a new pool for the mutex - ~LLMutex(); - - void lock(); // blocks - void unlock(); - bool isLocked(); // non-blocking, but does do a lock/unlock so not free - -protected: - apr_thread_mutex_t *mAPRMutexp; - apr_pool_t *mAPRPoolp; - BOOL mIsLocalPool; -#if MUTEX_DEBUG - std::map<U32, BOOL> mIsLocked; -#endif -}; - -// Actually a condition/mutex pair (since each condition needs to be associated with a mutex). -class LL_COMMON_API LLCondition : public LLMutex -{ -public: - LLCondition(apr_pool_t *apr_poolp); // Defaults to global pool, could use the thread pool as well. - ~LLCondition(); - - void wait(); // blocks - void signal(); - void broadcast(); - -protected: - apr_thread_cond_t *mAPRCondp; -}; - -class LLMutexLock -{ -public: - LLMutexLock(LLMutex* mutex) - { - mMutex = mutex; - mMutex->lock(); - } - ~LLMutexLock() - { - mMutex->unlock(); - } -private: - LLMutex* mMutex; -}; - -//============================================================================ - -void LLThread::lockData() -{ - mRunCondition->lock(); -} - -void LLThread::unlockData() -{ - mRunCondition->unlock(); -} - - -//============================================================================ - -// see llmemory.h for LLPointer<> definition - -class LL_COMMON_API LLThreadSafeRefCount -{ -public: - static void initThreadSafeRefCount(); // creates sMutex - static void cleanupThreadSafeRefCount(); // destroys sMutex - -private: - static LLMutex* sMutex; - -private: - LLThreadSafeRefCount(const LLThreadSafeRefCount&); // not implemented - LLThreadSafeRefCount&operator=(const LLThreadSafeRefCount&); // not implemented - -protected: - virtual ~LLThreadSafeRefCount(); // use unref() - -public: - LLThreadSafeRefCount(); - - void ref() - { - if (sMutex) sMutex->lock(); - mRef++; - if (sMutex) sMutex->unlock(); - } - - S32 unref() - { - llassert(mRef >= 1); - if (sMutex) sMutex->lock(); - S32 res = --mRef; - if (sMutex) sMutex->unlock(); - if (0 == res) - { - delete this; - return 0; - } - return res; - } - S32 getNumRefs() const - { - return mRef; - } - -private: - S32 mRef; -}; - -//============================================================================ - -// Simple responder for self destructing callbacks -// Pure virtual class -class LL_COMMON_API LLResponder : public LLThreadSafeRefCount -{ -protected: - virtual ~LLResponder(); -public: - virtual void completed(bool success) = 0; -}; - -//============================================================================ - -#endif // LL_LLTHREAD_H +/**
+ * @file llthread.h
+ * @brief Base classes for thread, mutex and condition handling.
+ *
+ * $LicenseInfo:firstyear=2004&license=viewergpl$
+ *
+ * Copyright (c) 2004-2009, Linden Research, Inc.
+ *
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab. Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ *
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at
+ * http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ *
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ *
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#ifndef LL_LLTHREAD_H
+#define LL_LLTHREAD_H
+
+#include "llapp.h"
+#include "llapr.h"
+#include "apr_thread_cond.h"
+
+class LLThread;
+class LLMutex;
+class LLCondition;
+
+#if LL_WINDOWS
+#define ll_thread_local __declspec(thread)
+#else
+#define ll_thread_local __thread
+#endif
+
+class LL_COMMON_API LLThread
+{
+private:
+ static U32 sIDIter;
+
+public:
+ typedef enum e_thread_status
+ {
+ STOPPED = 0, // The thread is not running. Not started, or has exited its run function
+ RUNNING = 1, // The thread is currently running
+ QUITTING= 2 // Someone wants this thread to quit
+ } EThreadStatus;
+
+ LLThread(const std::string& name, apr_pool_t *poolp = NULL);
+ virtual ~LLThread(); // Warning! You almost NEVER want to destroy a thread unless it's in the STOPPED state.
+ virtual void shutdown(); // stops the thread
+
+ bool isQuitting() const { return (QUITTING == mStatus); }
+ bool isStopped() const { return (STOPPED == mStatus); }
+
+ static U32 currentID(); // Return ID of current thread
+ static void yield(); // Static because it can be called by the main thread, which doesn't have an LLThread data structure.
+
+public:
+ // PAUSE / RESUME functionality. See source code for important usage notes.
+ // Called from MAIN THREAD.
+ void pause();
+ void unpause();
+ bool isPaused() { return isStopped() || mPaused == TRUE; }
+
+ // Cause the thread to wake up and check its condition
+ void wake();
+
+ // Same as above, but to be used when the condition is already locked.
+ void wakeLocked();
+
+ // Called from run() (CHILD THREAD). Pause the thread if requested until unpaused.
+ void checkPause();
+
+ // this kicks off the apr thread
+ void start(void);
+
+ apr_pool_t *getAPRPool() { return mAPRPoolp; }
+ LLVolatileAPRPool* getLocalAPRFilePool() { return mLocalAPRFilePoolp ; }
+
+ U32 getID() const { return mID; }
+
+private:
+ BOOL mPaused;
+
+ // static function passed to APR thread creation routine
+ static void *APR_THREAD_FUNC staticRun(apr_thread_t *apr_threadp, void *datap);
+
+protected:
+ std::string mName;
+ LLCondition* mRunCondition;
+
+ apr_thread_t *mAPRThreadp;
+ apr_pool_t *mAPRPoolp;
+ BOOL mIsLocalPool;
+ EThreadStatus mStatus;
+ U32 mID;
+
+ //a local apr_pool for APRFile operations in this thread. If it exists, LLAPRFile::sAPRFilePoolp should not be used.
+ //Note: this pool is used by APRFile ONLY, do NOT use it for any other purposes.
+ // otherwise it will cause severe memory leaking!!! --bao
+ LLVolatileAPRPool *mLocalAPRFilePoolp ;
+
+ void setQuitting();
+
+ // virtual function overridden by subclass -- this will be called when the thread runs
+ virtual void run(void) = 0;
+
+ // virtual predicate function -- returns true if the thread should wake up, false if it should sleep.
+ virtual bool runCondition(void);
+
+ // Lock/Unlock Run Condition -- use around modification of any variable used in runCondition()
+ inline void lockData();
+ inline void unlockData();
+
+ // This is the predicate that decides whether the thread should sleep.
+ // It should only be called with mRunCondition locked, since the virtual runCondition() function may need to access
+ // data structures that are thread-unsafe.
+ bool shouldSleep(void) { return (mStatus == RUNNING) && (isPaused() || (!runCondition())); }
+
+ // To avoid spurious signals (and the associated context switches) when the condition may or may not have changed, you can do the following:
+ // mRunCondition->lock();
+ // if(!shouldSleep())
+ // mRunCondition->signal();
+ // mRunCondition->unlock();
+};
+
+//============================================================================
+
+#define MUTEX_DEBUG (LL_DEBUG || LL_RELEASE_WITH_DEBUG_INFO)
+
+class LL_COMMON_API LLMutex
+{
+public:
+ typedef enum
+ {
+ NO_THREAD = 0xFFFFFFFF
+ } e_locking_thread;
+
+ LLMutex(apr_pool_t *apr_poolp); // NULL pool constructs a new pool for the mutex
+ ~LLMutex();
+
+ void lock(); // blocks
+ void unlock();
+ bool isLocked(); // non-blocking, but does do a lock/unlock so not free
+ U32 lockingThread() const; //get ID of locking thread
+
+protected:
+ apr_thread_mutex_t *mAPRMutexp;
+ mutable U32 mCount;
+ mutable U32 mLockingThread;
+
+ apr_pool_t *mAPRPoolp;
+ BOOL mIsLocalPool;
+
+#if MUTEX_DEBUG
+ std::map<U32, BOOL> mIsLocked;
+#endif
+};
+
+// Actually a condition/mutex pair (since each condition needs to be associated with a mutex).
+class LL_COMMON_API LLCondition : public LLMutex
+{
+public:
+ LLCondition(apr_pool_t *apr_poolp); // Defaults to global pool, could use the thread pool as well.
+ ~LLCondition();
+
+ void wait(); // blocks
+ void signal();
+ void broadcast();
+
+protected:
+ apr_thread_cond_t *mAPRCondp;
+};
+
+class LLMutexLock
+{
+public:
+ LLMutexLock(LLMutex* mutex)
+ {
+ mMutex = mutex;
+ mMutex->lock();
+ }
+ ~LLMutexLock()
+ {
+ mMutex->unlock();
+ }
+private:
+ LLMutex* mMutex;
+};
+
+//============================================================================
+
+void LLThread::lockData()
+{
+ mRunCondition->lock();
+}
+
+void LLThread::unlockData()
+{
+ mRunCondition->unlock();
+}
+
+
+//============================================================================
+
+// see llmemory.h for LLPointer<> definition
+
+class LL_COMMON_API LLThreadSafeRefCount
+{
+public:
+ static void initThreadSafeRefCount(); // creates sMutex
+ static void cleanupThreadSafeRefCount(); // destroys sMutex
+
+private:
+ static LLMutex* sMutex;
+
+private:
+ LLThreadSafeRefCount(const LLThreadSafeRefCount&); // not implemented
+ LLThreadSafeRefCount&operator=(const LLThreadSafeRefCount&); // not implemented
+
+protected:
+ virtual ~LLThreadSafeRefCount(); // use unref()
+
+public:
+ LLThreadSafeRefCount();
+
+ void ref()
+ {
+ if (sMutex) sMutex->lock();
+ mRef++;
+ if (sMutex) sMutex->unlock();
+ }
+
+ S32 unref()
+ {
+ llassert(mRef >= 1);
+ if (sMutex) sMutex->lock();
+ S32 res = --mRef;
+ if (sMutex) sMutex->unlock();
+ if (0 == res)
+ {
+ delete this;
+ return 0;
+ }
+ return res;
+ }
+ S32 getNumRefs() const
+ {
+ return mRef;
+ }
+
+private:
+ S32 mRef;
+};
+
+//============================================================================
+
+// Simple responder for self destructing callbacks
+// Pure virtual class
+class LL_COMMON_API LLResponder : public LLThreadSafeRefCount
+{
+protected:
+ virtual ~LLResponder();
+public:
+ virtual void completed(bool success) = 0;
+};
+
+//============================================================================
+
+#endif // LL_LLTHREAD_H
diff --git a/indra/llcommon/stdenums.h b/indra/llcommon/stdenums.h index 1a5678dde1..6eead924da 100644 --- a/indra/llcommon/stdenums.h +++ b/indra/llcommon/stdenums.h @@ -55,7 +55,8 @@ enum EDragAndDropType DAD_ANIMATION = 12, DAD_GESTURE = 13, DAD_LINK = 14, - DAD_COUNT = 15, // number of types in this enum + DAD_MESH = 15, + DAD_COUNT = 16, // number of types in this enum }; // Reasons for drags to be denied. |