#!/bin/bash
# Copyright (c) 2016 PaddlePaddle Authors. All Rights Reserved
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

PORT_FILE=/tmp/paddle_test_ports
PORT_LOCK_FILE=/tmp/paddle_test_ports.lock

# Create flag file, all user can rw, ignore all error here
touch $PORT_FILE $PORT_LOCK_FILE 2>/dev/null
chmod a+rw $PORT_FILE $PORT_LOCK_FILE 2>/dev/null

# acquire a range of ports that not used by other runtests.sh currently.
# return 1 if ports is used by other, otherwise return 0.
# NOTE: the acquire_ports/release_ports is interprocess mutexed.
#
# There are two parameter of this method
# param 1: the begin of port range
# param 2: the length of port range.
# so, the port range is [param1, param1+param2)
acquire_ports(){
  (
    flock -x 200
    let "len=$1+$2"
    for((i=$1; i<$len; i++))
    do
      grep -q $i $PORT_FILE
      if [ $? -eq 0 ] ; then
        return 1 # Port already write to $PORT_FILE
      fi
    done

    for((i=$1; i<$len; i++))
    do
      echo $i >> $PORT_FILE # Write to $PORT_FILE
    done
    return 0
  )200>$PORT_LOCK_FILE
}

# release a range of ports. Mark these ports is not used by runtests.sh.
# NOTE: the acquire_ports/release_ports is interprocess mutexed.
#
# The parameter is same as acquire_ports, see acquire_ports' comments.
release_ports(){
  (
    flock -x 200
    let "len=$1+$2"
    for((i=$1; i<$len; i++))
    do
      tmp=`sed "/$i/d" $PORT_FILE`  # remove port
      echo $tmp > $PORT_FILE
    done
  )200>$PORT_LOCK_FILE
}

# use set_port  to get a random free port
# such as    set_port -p port test_fuc   to run  test_fuc --port=random
# use  -n to set_port test_fuc to get a continuous free port
# such as    set_port  -n 10 -p port  test_fuc  to get ten continuous free port to run test_fuc --port=random
set_port()
{
    num=1

    port_type="port"
    unset OPTIND
    while   getopts  "n:p:"  opt
    do
        case  "$opt"   in
            n)   echo  "get num ${OPTARG}"
                 num=${OPTARG}
                 ;;
            p)   echo  "get port_type ${OPTARG}"
                 port_type=${OPTARG}
                 ;;
        esac
    done
    shift $((OPTIND-1))
    cmd=$@
    for ((i=1;i<=10000;i++))
    do
        declare -i port=$RANDOM+10000
        port_used_total=0
        for((n=0;n<=num-1;n++))
            do
                declare -i port_check=$port+$n
                port_used_num=`netstat -a |grep $port_check|wc -l`
                declare -i port_used_total=$port_used_total+$port_used_num
            done
        if [ $port_used_total -ne 0 ]
            then
                continue
        fi
        # Lock Ports.
        acquire_ports $port $num
        if [ $? -ne 0 ]; then
            continue
        fi
        $cmd --$port_type=$port
        return_val=$?
        release_ports $port $num
        if [ $return_val -eq 0 ]; then
            return 0
        else
            echo "$cmd run wrong"
            return 1
        fi
    done

}
