On Tue, Aug 11, 2015 at 08:26:33AM +0900, Minchan Kim wrote: > Hi Joonsoo, > > On Mon, Aug 10, 2015 at 09:32:30AM +0900, Joonsoo Kim wrote: > > On Fri, Aug 07, 2015 at 06:58:16PM +0900, Sergey Senozhatsky wrote: > > > On (08/07/15 18:14), Sergey Senozhatsky wrote: > > > > hm... I need to think about it more. > > > > > > > > we do wake_up every time we put stream back to the list > > > > > > > > zcomp_strm_multi_release(): > > > > > > > > spin_lock(&zs->strm_lock); > > > > if (zs->avail_strm <= zs->max_strm) { > > > > list_add(&zstrm->list, &zs->idle_strm); > > > > spin_unlock(&zs->strm_lock); > > > > wake_up(&zs->strm_wait); > > > > return; > > > > } > > > > > > > > > > > > but I can probably see what you mean... in some very extreme case, > > > > though. I can't even formulate it... eh... we use a multi stream > > > > backend with ->max_strm == 1 and there are two processes, one > > > > just falsely passed the wait_event() `if (condition)' check, the > > > > other one just put stream back to ->idle_strm and called wake_up(), > > > > but the first process hasn't yet executed prepare_to_wait_event() > > > > so it might miss a wakeup. and there should be no other process > > > > doing read or write operation. otherwise, there will be wakeup > > > > eventually. > > > > > > > > is this the case you were thinking of?... then yes, this spinlock > > > > may help. > > > > > > > > > > on the other hand... it's actually > > > > > > wait_event() is > > > > > > if (condition) > > > break; > > > prepare_to_wait_event(&wq, &__wait, state) > > > if (condition) > > > break; > > > schedule(); > > > > > > if first condition check was false and we missed a wakeup call between > > > first condition and prepare_to_wait_event(), then second condition > > > check should do the trick I think (or you expect that second condition > > > check may be wrongly pre-fetched or something). > > > > Hello, Sergey. > > > > This is what I thought. > > I expected that second condition can be false if compiler reuse result > > of first check for optimization. I guess that there is no prevention > > for this kind of optimization. > > > > So, following is the problem sequence I thought. > > T1 means thread 1, T2 means another thread, 2. > > > > <T1-1> check if idle_strm is empty or not with holding the lock > > <T1-2> It is empty so do spin_unlock and run wait_event macro > > <T1-3> check if idle_strm is empty or not > > <T1-4> It is still empty > > > > <T2-1> do strm release > > <T2-2> call wake_up > > > > <T1-5> add T1 to wait queue > > <T1-6> check if idle_strm is empty or not > > <T1-7> compiler reuse <T1-4>'s result or CPU just fetch cached > > result so T1 starts waiting > > > > In this case, T1 can be sleep permanently. To prevent compiler > > optimization or fetching cached value, we need a lock here. > > When I read Documentation/memory-barrier.txt, it shouldn't happen. > > "All memory barriers except the data dependency barriers imply a compiler > barrier. Data dependencies do not impose any additional compiler ordering." > > "SLEEP AND WAKE-UP FUNCTIONS > --------------------------- > > Sleeping and waking on an event flagged in global data ... > ... > ... > ... > > A general memory barrier is interpolated automatically by set_current_state() > after it has altered the task state:" > > So I think your T1-7 assumption is not true. > > As well, there are many examples under drivers/ to use the global data > as event flag without locking or atomic. >
Okay. Now, I'm convinced that race is not possible. I will drop this patch. Thanks. -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/