2009-02-17 13:42:01 +03:00
/*
Unix SMB / CIFS implementation .
Infrastructure for async requests
Copyright ( C ) Volker Lendecke 2008
Copyright ( C ) Stefan Metzmacher 2009
* * NOTE ! The following LGPL license applies to the tevent
* * library . This does NOT imply that all of Samba is released
* * under the LGPL
This library is free software ; you can redistribute it and / or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation ; either
version 3 of the License , or ( at your option ) any later version .
This library is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the GNU
Lesser General Public License for more details .
You should have received a copy of the GNU Lesser General Public
License along with this library ; if not , see < http : //www.gnu.org/licenses/>.
*/
# include "replace.h"
# include "tevent.h"
# include "tevent_internal.h"
# include "tevent_util.h"
struct tevent_queue_entry {
struct tevent_queue_entry * prev , * next ;
struct tevent_queue * queue ;
bool triggered ;
struct tevent_req * req ;
2009-03-17 12:42:55 +03:00
struct tevent_context * ev ;
2009-02-17 13:42:01 +03:00
tevent_queue_trigger_fn_t trigger ;
void * private_data ;
} ;
struct tevent_queue {
const char * name ;
const char * location ;
bool running ;
2009-03-17 12:42:55 +03:00
struct tevent_immediate * immediate ;
2009-02-17 13:42:01 +03:00
size_t length ;
struct tevent_queue_entry * list ;
} ;
2009-03-17 12:42:55 +03:00
static void tevent_queue_immediate_trigger ( struct tevent_context * ev ,
struct tevent_immediate * im ,
void * private_data ) ;
2009-02-17 13:42:01 +03:00
static int tevent_queue_entry_destructor ( struct tevent_queue_entry * e )
{
struct tevent_queue * q = e - > queue ;
if ( ! q ) {
return 0 ;
}
DLIST_REMOVE ( q - > list , e ) ;
q - > length - - ;
2009-03-17 12:42:55 +03:00
if ( ! q - > running ) {
return 0 ;
}
if ( ! q - > list ) {
return 0 ;
}
if ( q - > list - > triggered ) {
return 0 ;
2009-02-17 13:42:01 +03:00
}
2009-03-17 12:42:55 +03:00
tevent_schedule_immediate ( q - > immediate ,
q - > list - > ev ,
tevent_queue_immediate_trigger ,
q ) ;
2009-02-17 13:42:01 +03:00
return 0 ;
}
static int tevent_queue_destructor ( struct tevent_queue * q )
{
q - > running = false ;
while ( q - > list ) {
struct tevent_queue_entry * e = q - > list ;
talloc_free ( e ) ;
}
return 0 ;
}
struct tevent_queue * _tevent_queue_create ( TALLOC_CTX * mem_ctx ,
const char * name ,
const char * location )
{
struct tevent_queue * queue ;
queue = talloc_zero ( mem_ctx , struct tevent_queue ) ;
if ( ! queue ) {
return NULL ;
}
queue - > name = talloc_strdup ( queue , name ) ;
if ( ! queue - > name ) {
talloc_free ( queue ) ;
return NULL ;
}
2009-03-17 12:42:55 +03:00
queue - > immediate = tevent_create_immediate ( queue ) ;
if ( ! queue - > immediate ) {
talloc_free ( queue ) ;
return NULL ;
}
2009-02-17 13:42:01 +03:00
queue - > location = location ;
/* queue is running by default */
queue - > running = true ;
talloc_set_destructor ( queue , tevent_queue_destructor ) ;
return queue ;
}
2009-03-17 12:42:55 +03:00
static void tevent_queue_immediate_trigger ( struct tevent_context * ev ,
struct tevent_immediate * im ,
void * private_data )
2009-02-17 13:42:01 +03:00
{
2013-12-05 11:47:27 +04:00
struct tevent_queue * q =
talloc_get_type_abort ( private_data ,
struct tevent_queue ) ;
2009-02-17 13:42:01 +03:00
2009-03-17 12:42:55 +03:00
if ( ! q - > running ) {
return ;
}
2009-02-17 13:42:01 +03:00
2014-01-11 11:58:05 +04:00
if ( ! q - > list ) {
return ;
}
2009-02-17 13:42:01 +03:00
q - > list - > triggered = true ;
q - > list - > trigger ( q - > list - > req , q - > list - > private_data ) ;
}
2011-08-09 17:33:37 +04:00
static struct tevent_queue_entry * tevent_queue_add_internal (
struct tevent_queue * queue ,
struct tevent_context * ev ,
struct tevent_req * req ,
tevent_queue_trigger_fn_t trigger ,
2011-07-28 12:45:22 +04:00
void * private_data ,
bool allow_direct )
2009-02-17 13:42:01 +03:00
{
struct tevent_queue_entry * e ;
e = talloc_zero ( req , struct tevent_queue_entry ) ;
if ( e = = NULL ) {
2011-08-09 17:33:37 +04:00
return NULL ;
2009-02-17 13:42:01 +03:00
}
e - > queue = queue ;
e - > req = req ;
2009-03-17 12:42:55 +03:00
e - > ev = ev ;
2009-02-17 13:42:01 +03:00
e - > trigger = trigger ;
e - > private_data = private_data ;
2011-07-28 11:45:15 +04:00
/*
* if there is no trigger , it is just a blocker
*/
if ( trigger = = NULL ) {
e - > triggered = true ;
}
2011-07-28 12:45:22 +04:00
if ( queue - > length > 0 ) {
/*
* if there are already entries in the
* queue do not optimize .
*/
allow_direct = false ;
}
if ( req - > async . fn ! = NULL ) {
/*
2016-08-19 17:18:56 +03:00
* If the caller wants to optimize for the
2011-07-28 12:45:22 +04:00
* empty queue case , call the trigger only
* if there is no callback defined for the
* request yet .
*/
allow_direct = false ;
}
2016-02-05 13:37:42 +03:00
DLIST_ADD_END ( queue - > list , e ) ;
2009-02-17 13:42:01 +03:00
queue - > length + + ;
talloc_set_destructor ( e , tevent_queue_entry_destructor ) ;
2009-03-17 12:42:55 +03:00
if ( ! queue - > running ) {
2011-08-09 17:33:37 +04:00
return e ;
2009-03-17 12:42:55 +03:00
}
if ( queue - > list - > triggered ) {
2011-08-09 17:33:37 +04:00
return e ;
2009-03-17 12:42:55 +03:00
}
2011-07-28 12:45:22 +04:00
/*
* If allowed we directly call the trigger
* avoiding possible delays caused by
* an immediate event .
*/
if ( allow_direct ) {
queue - > list - > triggered = true ;
queue - > list - > trigger ( queue - > list - > req ,
queue - > list - > private_data ) ;
return e ;
}
2009-03-17 12:42:55 +03:00
tevent_schedule_immediate ( queue - > immediate ,
queue - > list - > ev ,
tevent_queue_immediate_trigger ,
queue ) ;
2011-08-09 17:33:37 +04:00
return e ;
}
bool tevent_queue_add ( struct tevent_queue * queue ,
struct tevent_context * ev ,
struct tevent_req * req ,
tevent_queue_trigger_fn_t trigger ,
void * private_data )
{
struct tevent_queue_entry * e ;
e = tevent_queue_add_internal ( queue , ev , req ,
2011-07-28 12:45:22 +04:00
trigger , private_data , false ) ;
2011-08-09 17:33:37 +04:00
if ( e = = NULL ) {
return false ;
}
2009-02-17 13:42:01 +03:00
return true ;
}
2011-07-28 12:45:22 +04:00
struct tevent_queue_entry * tevent_queue_add_entry (
struct tevent_queue * queue ,
struct tevent_context * ev ,
struct tevent_req * req ,
tevent_queue_trigger_fn_t trigger ,
void * private_data )
{
return tevent_queue_add_internal ( queue , ev , req ,
trigger , private_data , false ) ;
}
struct tevent_queue_entry * tevent_queue_add_optimize_empty (
struct tevent_queue * queue ,
struct tevent_context * ev ,
struct tevent_req * req ,
tevent_queue_trigger_fn_t trigger ,
void * private_data )
{
return tevent_queue_add_internal ( queue , ev , req ,
trigger , private_data , true ) ;
}
2018-02-15 16:47:25 +03:00
void tevent_queue_entry_untrigger ( struct tevent_queue_entry * entry )
{
if ( entry - > queue - > running ) {
abort ( ) ;
}
if ( entry - > queue - > list ! = entry ) {
abort ( ) ;
}
entry - > triggered = false ;
}
2009-03-17 12:42:55 +03:00
void tevent_queue_start ( struct tevent_queue * queue )
2009-02-17 13:42:01 +03:00
{
if ( queue - > running ) {
/* already started */
2009-03-17 12:42:55 +03:00
return ;
2009-02-17 13:42:01 +03:00
}
2009-03-17 12:42:55 +03:00
queue - > running = true ;
if ( ! queue - > list ) {
return ;
2009-02-17 13:42:01 +03:00
}
2009-03-17 12:42:55 +03:00
if ( queue - > list - > triggered ) {
return ;
}
2009-02-17 13:42:01 +03:00
2009-03-17 12:42:55 +03:00
tevent_schedule_immediate ( queue - > immediate ,
queue - > list - > ev ,
tevent_queue_immediate_trigger ,
queue ) ;
2009-02-17 13:42:01 +03:00
}
void tevent_queue_stop ( struct tevent_queue * queue )
{
queue - > running = false ;
}
size_t tevent_queue_length ( struct tevent_queue * queue )
{
return queue - > length ;
}
2011-07-28 11:46:34 +04:00
bool tevent_queue_running ( struct tevent_queue * queue )
{
return queue - > running ;
}
2013-09-19 17:14:25 +04:00
struct tevent_queue_wait_state {
uint8_t dummy ;
} ;
static void tevent_queue_wait_trigger ( struct tevent_req * req ,
void * private_data ) ;
struct tevent_req * tevent_queue_wait_send ( TALLOC_CTX * mem_ctx ,
struct tevent_context * ev ,
struct tevent_queue * queue )
{
struct tevent_req * req ;
struct tevent_queue_wait_state * state ;
bool ok ;
req = tevent_req_create ( mem_ctx , & state ,
struct tevent_queue_wait_state ) ;
if ( req = = NULL ) {
return NULL ;
}
ok = tevent_queue_add ( queue , ev , req ,
tevent_queue_wait_trigger ,
NULL ) ;
if ( ! ok ) {
2013-12-15 23:40:06 +04:00
tevent_req_oom ( req ) ;
2013-09-19 17:14:25 +04:00
return tevent_req_post ( req , ev ) ;
}
return req ;
}
static void tevent_queue_wait_trigger ( struct tevent_req * req ,
void * private_data )
{
tevent_req_done ( req ) ;
}
bool tevent_queue_wait_recv ( struct tevent_req * req )
{
enum tevent_req_state state ;
uint64_t err ;
if ( tevent_req_is_error ( req , & state , & err ) ) {
tevent_req_received ( req ) ;
return false ;
}
tevent_req_received ( req ) ;
return true ;
}