sessionset.c 6.79 KB
Newer Older
aymeric's avatar
aymeric committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
/*
  The oRTP library is an RTP (Realtime Transport Protocol - rfc1889) stack.
  Copyright (C) 2001  Simon MORLAT simon.morlat@linphone.org

  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 2.1 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, write to the Free Software
  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/

#include <ortp/ortp.h>
#include <ortp/sessionset.h>
#include "scheduler.h"


/**
 * Allocates and initialize a new empty session set.
 *
 * @return the empty session set.
**/
SessionSet * session_set_new()
{
	SessionSet *set=(SessionSet *) ortp_malloc(sizeof(SessionSet));
	session_set_init(set);
	return set;
}


/**
 * Destroys a session set.
 *
**/

void session_set_destroy(SessionSet *set)
{
	ortp_free(set);
}

48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68
int count_power_items_simple(int v) 
{
    int c = 0,j;
    for (j=0;j<32;j++){
        if ( ((v)>>j) & 1){
	    ++c;
        }
    }
    return c;
}

int count_power_items_fast(int v) 
{
    int c = 0;
    while(v) {
        c += (v & 1);
	v >>= 1;
    }
    return c;
}

aymeric's avatar
aymeric committed
69 70 71 72
int session_set_and(SessionSet *sched_set, int maxs, SessionSet *user_set, SessionSet *result_set)
{
	uint32_t *mask1,*mask2,*mask3;
	int i=0;
73
	int ret=0;
aymeric's avatar
aymeric committed
74 75 76 77 78 79 80
	mask1=(uint32_t*)(void*)&sched_set->rtpset;
	mask2=(uint32_t*)(void*)&user_set->rtpset;
	mask3=(uint32_t*)(void*)&result_set->rtpset;
	while(i<maxs+1){
		*mask3=(*mask1) & (*mask2);	/* computes the AND between the two masks*/
		/* and unset the sessions that have been found from the sched_set */
		*mask1=(*mask1) & (~(*mask3));
81
		ret += count_power_items_fast(*mask3);
aymeric's avatar
aymeric committed
82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163
		i+=32;
		mask1++;
		mask2++;
		mask3++;
	}
	//printf("session_set_and: ret=%i\n",ret);
	return ret;
}

/**
 *	This function performs similarly as libc select() function, but performs on #RtpSession 
 *	instead of file descriptors.
 *	session_set_select() suspends the calling process until some events arrive on one of the
 *	three sets passed in argument. Two of the sets can be NULL.
 *	The first set @recvs is interpreted as a set of RtpSession waiting for receive events:
 *	a new buffer (perhaps empty) is availlable on one or more sessions of the set, or the last
 *	receive operation with rtp_session_recv_with_ts() would have finished if it were in 
 *	blocking mode.
 *	The second set is interpreted as a set of RtpSession waiting for send events, i.e. the last
 *	rtp_session_send_with_ts() call on a session would have finished if it were in blocking mode.
 *	
 *	When some events arrived on some of sets, then the function returns and sets are changed
 *	to indicate the sessions where events happened.
 *	Sessions can be added to sets using session_set_set(), a session has to be tested to be 
 *	part of a set using session_set_is_set().
 *
 * @param recvs a set of rtp sessions to be watched for read events
 * @param sends a set of rtp sessions to be watched for write events
 * @param errors a set of rtp sessions to be watched for errors
 * @return: the number of sessions on which the selected events happened.
**/
int session_set_select(SessionSet *recvs, SessionSet *sends, SessionSet *errors)
{
	int ret=0,bits;
	SessionSet temp;
	RtpScheduler *sched=ortp_get_scheduler();
	
	/*lock the scheduler to not read the masks while they are being modified by the scheduler*/
	rtp_scheduler_lock(sched);
	
	while(1){
		/* computes the SessionSet intersection (in the other words mask intersection) between
		the mask given by the user and scheduler masks */
		if (recvs!=NULL){
			session_set_init(&temp);
			bits=session_set_and(&sched->r_sessions,sched->all_max,recvs,&temp);
			ret+=bits;
			/* copy the result set in the given user set (might be empty) */
			if (ret>0) session_set_copy(recvs,&temp);
		}
		if (sends!=NULL){
			session_set_init(&temp);
			bits=session_set_and(&sched->w_sessions,sched->all_max,sends,&temp);
			ret+=bits;
			if (ret>0){
				/* copy the result set in the given user set (might be empty)*/
				session_set_copy(sends,&temp);
			}
		}
		if (errors!=NULL){
			session_set_init(&temp);
			bits=session_set_and(&sched->e_sessions,sched->all_max,errors,&temp);
			ret+=bits;
			if (ret>0){
				/* copy the result set in the given user set */
				session_set_copy(errors,&temp);
			}
		}
		if (ret>0){
			/* there are set file descriptors, return immediately */
			//printf("There are %i sessions set, returning.\n",ret);
			rtp_scheduler_unlock(sched);
			return ret;
		}
		//printf("There are %i sessions set.\n",ret);
		/* else we wait until the next loop of the scheduler*/
		ortp_cond_wait(&sched->unblock_select_cond,&sched->lock);
	}

	return -1;
}

164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216
int session_set_timedselect(SessionSet *recvs, SessionSet *sends, SessionSet *errors,  struct timeval *timeout)
{
	int ret=0,bits;
	int remainingTime; // duration in ms
	SessionSet temp;
	RtpScheduler *sched;
	if (timeout==NULL)
		return session_set_select(recvs, sends, errors);
	sched=ortp_get_scheduler();
	remainingTime = timeout->tv_usec/1000 + timeout->tv_sec*1000;

	/*lock the scheduler to not read the masks while they are being modified by the scheduler*/
	rtp_scheduler_lock(sched);

	do {
		/* computes the SessionSet intersection (in the other words mask intersection) between
		the mask given by the user and scheduler masks */
		if (recvs!=NULL){
			session_set_init(&temp);
			bits=session_set_and(&sched->r_sessions,sched->all_max,recvs,&temp);
			ret+=bits;
			/* copy the result set in the given user set (might be empty) */
			if (ret>0) session_set_copy(recvs,&temp);
		}
		if (sends!=NULL){
			session_set_init(&temp);
			bits=session_set_and(&sched->w_sessions,sched->all_max,sends,&temp);
			ret+=bits;
			if (ret>0){
				/* copy the result set in the given user set (might be empty)*/
				session_set_copy(sends,&temp);
			}
		}
		if (errors!=NULL){
			session_set_init(&temp);
			bits=session_set_and(&sched->e_sessions,sched->all_max,errors,&temp);
			ret+=bits;
			if (ret>0){
				/* copy the result set in the given user set */
				session_set_copy(errors,&temp);
			}
		}
		if (ret>0){
			/* there are set file descriptors, return immediately */
			//printf("There are %i sessions set, returning.\n",ret);
			rtp_scheduler_unlock(sched);
			return ret;
		}
		//printf("There are %i sessions set.\n",ret);
		/* else we wait until the next loop of the scheduler*/
		ortp_cond_wait(&sched->unblock_select_cond,&sched->lock);
		remainingTime -= sched->timer_inc;
	} while (remainingTime>0);
Simon Morlat's avatar
Simon Morlat committed
217
	rtp_scheduler_unlock(sched);
218 219 220

	return -1;
}