Archive

Archive for the ‘IT’ Category

Programmer’s Corner: A Rationale for C++0x’s Rvalue-References

December 18th, 2010 No comments

Arguably one of the more advanced features of the upcoming C++0x standard are the so-called rvalue-references. A few months ago, we were discussing an example of what unpleasant issues one can run into in a world without rvalue-references. In this article, we will try to give a more extensive rationale for why we need another type of references in C++ and how they are specified in the current draft of the standard.

Why References?

When it comes to passing arguments, most modern programming languages already made the choice for you: Built-in types are passed by value, complex types by reference. In C++, things are more complicated, as a programmer may choose between passing by-value, by-pointer or by-reference.

The first two are natural heritage from C. References may seem kind of redundant at a first glance, since they  behave almost exactly like (const) pointers from a semantic point of view. And indeed the initial motivation for references came from a purely syntactic problem, namely that of operator overloading for complex types:

class MyType {
 ...
public:
  MyType operator+(MyType& rhs) const;
};
 
MyType a, b, c;
a = b + c;

This natural way of using operators can not be achieved with pointers alone (which would require explicit address operators on the caller’s side) . While there are further differences between pointers and references, this remains the most prominent example of why the low-level concept of raw-memory pointers is no longer sufficient in the context of higher-level C++ code.

References and Rvalues

However, the initial implementation of References had a severe problem, as it allowed binding to rvalues:

// side-effect: increments the passed variable
void increment(long& l) {
   ++l;
}
 
[...]
int i = 41;
increment(i);
//expected: i == 42

This is actually a very subtle error. Since C++ inherited the complex integer conversion rules from C, the compiler may easily resolve the call to increment(), by implicitly casting the int to long, creating an unnamed temporary (i.e. an rvalue) in the process. However, all side effects produced by the function call now get applied to that unnamed temporary instead of the initial int, so the function really has no effect on the int at all.

In order to avoid this pitfall while maintaining the powerful syntax of references, the 2.0 release of C++ from 1989 prohibited binding of non-const references to rvalues. This is the behavior that is still in use today and this is also the behavior that caused trouble in the previous article.

Introducing: Rvalue-References

In C++98, we distinguished between pointers (raw memory addresses), references (alias for a named value) and the special case of const-references (same as reference but may bind to an unnamed value as well).

As it turns out, it is indeed required to introduce another type of references, a non-const reference that binds to unnamed temporaries and unnamed temporaries only: Rvalue-references. Actually, the initial draft allowed rvalue-references to bind to lvalues as well, but that turned out to cause more trouble than good, so by the current draft, rvalue-references may indeed only bind to rvalues.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class MyType {
public:
  /* Constructor
   */
  MyType(int dummy);
  /* Copy constructor; uses const-lvalue-reference
   */
  MyType(MyType const& t);
  /* Move constructor; uses rvalue-references (new in C++0x)
   */
  MyType(MyType&& t);
};
 
int main()
{
    MyType a(42);   //construction
    MyType a_copy(a);  //copy construction
    MyType a_moved(MyType(42));  //move construction from rvalue
}

Before we take a look at some of the actual use-cases for this feature, we need to cover one subtle yet very important detail: Although an rvalue-reference ever only binds to rvalues, it is itself an ordinary lvalue as long as its named. Consider the following function:

void take_by_rvalref(MyType&& p)
{
    MyType p_copy(p);  // *no* move construction!
}

Although the parameter is passed as an rvalue-reference, p_copy is constructed using the copy-constructor, since p is itself an lvalue. This is similar to how a const reference always behaves like a (const) lvalue, even if it was bound to an rvalue by the caller.

In certain situations, it may be desirable to treat p as an rvalue to enforce invocation of the move-constructor, which we will cover below.

Move Semantics

With rvalue references, we can resolve the problem from our last article. Assuming we have an object of class Guard that is responsible for freeing a resource upon destruction, we ran into trouble when trying to write a factory method that returns resources encapsulated by Guards:

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
class Guard {
private:
	int resource_;
public:
	Guard(int r)
		:resource_(r)
	{
		::std::cout << this << " Guard Constructor" << ::std::endl;
		::std::cout << this << " *** Guarding " << resource_ << ::std::endl;
	}
	~Guard()
	{
		::std::cout << this << " Guard Destructor" << ::std::endl;
		if(resource_ > 0) {
			::std::cout << this << " *** Free " << resource_ << ::std::endl;
		}
	}
	Guard(Guard& rhs)
		:resource_(rhs.Detach())
	{
		::std::cout << this << " Copy constructor; Assuming ownership of " 
					<< resource_ << ::std::endl;
	}
private:
	int Detach()
	{
		::std::cout << this << " Detaching " << resource_ << ::std::endl;
		int ret = resource_;
		resource_ = 0;
		return ret;
	}
};
 
class Factory {
public:
	Guard BuildGuard()
	{
		return Guard(42);
		//error: can not copy-construct from unnamed temporary Guard
	}
};

With rvalue-references, we resolve the issue by introducing a move constructor:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class Guard {
	[...]
public:
	Guard(Guard&& rhs)
		:resource_(rhs.Detach())
	{
		::std::cout << this << " Guard Move Constructor" << ::std::endl;
		::std::cout << " Assuming ownership of " << resource_ << ::std::endl;
	}
};
 
class Factory {
public:
	Guard BuildGuard()
	{
		return Guard(42);
		//fine: invokes move-constructor Guard(Guard&&)
	}
};

Actually, on both VC2010 and gcc 4.3.4 this makes RVO kick in, so you probably won’t see the output from the move-constructor on the console.

Another use for move semantics is the elimination of spurious copies. Let’s assume for a moment that copy constructing a Guard would be horribly expensive, so things like the following become undesirable:

1
2
3
4
5
6
7
8
9
10
Guard BuildGuard()
{
	Guard g(42);
 
	//do some fancy stuff with g
	// [...]
 
	return g;
	//bad: implicit copy construction
}

Unless we get lucky with the compiler, we will have to pay for the copy-construction here. This is very annyoing, especially regarding that the local source of the copy will be destroyed immediately after the copying is finished. In C++98 the usual workaround for this would be to pass a Guard* as output argument to the function. However, no one likes output arguments, as they are clumsy to use and make your code hard to read.
In this case it would be nice to force the usage of the move constructor. Since moving allows to change the state of the source argument, it can be implemented very efficiently. For this case C++0x offers the std::move() function which converts its lvalue argument to an rvalue:

1
2
3
4
5
6
7
8
9
10
Guard BuildGuard()
{
	Guard g(42);
 
	//do some fancy stuff with g
	// [...]
 
	return ::std::move(g);
	//force move construction
}

Obviously, std::move() should only be used with extreme caution. It’s best to think of it as a special form of typecast that invalidates its source argument.

A nice property of move-semantics is, that we may omit the copy-constructor of an object altogether (i.e. specify a privately declared, unimplemented copy-constructor), creating types that are movable, but not copyable.

Perfect Forwarding

The last use is perhaps the most subtle one. Most C++-programmers will probably never need to make use of this feature directly, so feel free to skip this section if your head is already spinning with confusion.

Let’s return to our factory example once more and assume that Guard is to be constructed from some other object:

1
2
3
4
5
6
7
8
template<typename T>
Guard BuildGuard(T const& obj)
{
	Guard g(obj);
	// binds only to Guard(T const&)
	// [...]
	return ::std::move(g);
}

This works fine as long as the constructor of Guard is expecting a T const&. If for some reason it only accepts a non-const reference, we need to once again fall back to rvalue-references to allow passing of unnamed temporaries to BuildGuard():

1
2
3
4
5
6
7
8
template<typename T>
Guard BuildGuard(T&& o)
{
	Guard g(o);
	// also binds to Guard(T& o)
	// [...]
	return ::std::move(g);
}

The obvious disadvantage here is that the factory method now no longer works with lvalue arguments, at least not without an explicit std::move() on the caller’s side.
The only way to make it work for both cases is to implement two factory methods, which will result in an exponential interface blowup once the number of arguments increases.
Usually, this is not a problem, as Guard is likely to support only one of the two constructor types and we know beforehand which one that is going to be. Things only get ugly when Guard itself is a templated type, so we can not make any assumptions about its interface.
In order to handle this case, we need a way to preserve the const-ness of the argument bound to the rvalue-reference. This is taken care of by the std::forward() function-template:

1
2
3
4
5
6
7
8
9
template<typename T>
Guard BuildGuard(T&& o)
{
	Guard g(::std::forward<T>(o));
	// binds to either Guard(T&) or Guard(T const&),
	// depending on the type of the value bound by o
	// [...]
	return ::std::move(g);
}

One interesting side note about std::forward is that it only works with templated parameters: If the function is passed an unnamed temporary of type Foo, T resolves to Foo; if it is however passed an lvalue of type Foo, T resolves to Foo&! So the factory method in this case is actually passed (hold your breath!) an rvalue-reference to an unnamed temporary of type non-const lvalue-reference to Foo.
The std::forward function depends on this behavior of the template type deduction system to work correctly.

Conclusion

In this article, we discussed some of the decisions that determined the way references in C++ work today and gave a motivation for a new type of rvalue-references. We also gave a quick overview over some prominent uses for this new feature.
To conclude, let us take a quick look at what the most important benefits of rvalue-references are: First, they allow the implementation of movable types, which takes a lot of scare out of auto_ptr-like types. Also, move constructors eliminate a number of causes for spurious copies.
The main target audience for this feature are undoubtedly library developers. Even if you don’t change a single line of code, recompiling code that makes heavy use of the STL on an implementation that fully supports rvalue-references may result in a notable performance boost.

Literature:
Stroustrup, BjarneThe Design and Evolution of C++ (Addison Wesley)
Hinnant, Howard E.; Stroustrup, Bjarne; Kozicki, BronekA Brief Introduction to Rvalue References (N2027)

Categories: Programming

Programmer’s Corner: Resource Guards in C++

July 20th, 2010 No comments

Everyone familiar enough with C++ to call themselves proficient, will have experienced that living with that language becomes a lot easier when following the RAII-idiom frequently. For memory that means using things like ::std::auto_ptr<> or ::boost::shared_ptr<> regularly. For other resources it usually involves writing your own guard class.

Simple enough you might think, but there are a couple of unexpected pitfalls lurking along the way. Today I’d like to talk about some of the peculiarities involved in writing a guard class with transferable ownership in the style of ::std::auto_ptr<>.

To keep things simple, let us assume that we were dealing with resources in the form of postive integer identifiers. Many C-libraries use int in this way, take the BSD sockets API as a prominent example. A first shot at a guard class implementation might look like this:

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
#include <iostream>
 
class Guard {
private:
	int resource_;
public:
	Guard(int r)
		:resource_(r)
	{
		::std::cout << this << " Guard Constructor" << ::std::endl;
		::std::cout << this << " *** Guarding " << resource_ << ::std::endl;
	}
	~Guard()
	{
		::std::cout << this << " Guard Destructor" << ::std::endl;
		if(resource_ > 0) {
			::std::cout << this << " *** Free " << resource_ << ::std::endl;
		}
	}
	Guard(Guard const& rhs)
		:resource_(rhs.resource)
	{
		::std::cout << this << " Copy constructor" << ::std::endl;
	}
};
 
int main()
{
	{
		Guard g(42);
	}
	return 0;
}

The Guard will automatically free its associated resource upon destruction. However the current implementation has a dangerous flaw.

	{
		Guard g(42);
		Guard g_copy(g);
	}

Whenever we make a copy of Guard the underlying resource will be released multiple times. Depending on the type of resource this may or may not be bad, but it sure isn’t very pretty. To make this code work as expected, we introduce the concept of transferable ownership: Upon copy-construction the copy relieves the original Guard of resource ownership. Only the copy will be allowed to free the resource, while the orginal object has practically no responsibilities left. This is exactly the concept implemented by ::std::auto_ptr for memory.

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
#include <iostream>
 
class Guard {
private:
	int resource_;
public:
	Guard(int r)
		:resource_(r)
	{
		::std::cout << this << " Guard Constructor" << ::std::endl;
		::std::cout << this << " *** Guarding " << resource_ << ::std::endl;
	}
	~Guard()
	{
		::std::cout << this << " Guard Destructor" << ::std::endl;
		if(resource_ > 0) {
			::std::cout << this << " *** Free " << resource_ << ::std::endl;
		}
	}
	Guard(Guard& rhs)
		:resource_(rhs.Detach())
	{
		::std::cout << this << " Copy constructor; Assuming ownership of " 
					<< resource_ << ::std::endl;
	}
private:
	int Detach()
	{
		::std::cout << this << " Detaching " << resource_ << ::std::endl;
		int ret = resource_;
		resource_ = 0;
		return ret;
	}
};
 
int main()
{
	{
		Guard g(42);
		Guard g_copy(g);
	}
	return 0;
}

The modified code behaves as expected: Although two Guard objects are constructed, the guarded resource is only freed once. Note one subtle but important change in the interface: Since the copy-constructor must relieve the original object of its ownership, we can no longer take a const reference for copy-construction. As we will see shortly, this will get us into trouble.

Since this worked so well, let’s take things to the next level. Ever since Grandpa told us about encapsulation we have been a huge fan of it. With our guard class in place, we decide to write a factory method, so that we can hide those ugly int identifiers completely.

class Guard {
	[...]
};
 
class Factory {
public:
	Guard BuildGuard()
	{
		return Guard(42);
	}
};
 
int main()
{
	{
		Factory f;
		Guard g(f.BuildGuard());
	}
	return 0;
}

Can you spot the error? Actually this is a subtle one. It might very well work on your compiler due to excessive RVO, but according to the standard, this is not valid C++. The problem is that Factory::BuildGuard() needs to perform copy-construction from an unnamed temporary. As you may recall, unnamed temporaries are r-values in C++, which imposes certain restrictions. Most importantly, one can not take a non-const reference of an r-value! However, as we have seen earlier, the concept of transferable ownership requires the copy-constructor to take a non-const argument. Deadlocked.

So, how can we resolve this? A careless programmer might make declare Guard‘s resource_ field mutable, thus allowing Detach() to become a const-method, which will in turn allow the copy-constructor to take a const& parameter again. This is of course a very bad idea. Aside from the obvious interface inconsistencies introduced by making Detach() const (PLA anyone?), we lose one of the most useful idioms associated with these kind of containers: If you declare a container with transferable ownership const, you guarantee that the container never loses ownership of its resource. When the resource is fully encapsulated, it further guarantees that the container is the only object owning that resource. With ::std::auto_ptr, this is known as the const auto_ptr-idiom and is one of the main reasons why this container is still so popular, despite its flaws.

Talking about auto_ptr, how does the STL get around this problem? By introducing another proxy class! And that is exactly what we need to do as well. We can not copy-construct from unnamed temporaries, because we cannot transfer ownership from const objects. But what we can do is transfer ownership from an unnamed temporary guard object to another class of which we can copy-construct. Introducing GuardRef:

class GuardRef {
	friend class Guard;
private:
	int resource_;
private:
	GuardRef(int r)
		:resource_(r)
	{
		::std::cout << this << " GuardRef Constructor: " << resource_ << ::std::endl;
	}
public:
	GuardRef(GuardRef const& rhs)
		:resource_(rhs.resource_)
	{
		::std::cout << this << " GuardRef Copy Constructor: " << resource_ << ::std::endl;
	}
	~GuardRef()
	{
		::std::cout << this << " GuardRef Destructor" << ::std::endl;
	}
};

Note that GuardRef stores an integer resource just like Guard does, but it does not free the resource upon destruction. Thus there is no reason to transfer ownership between GuardRefs on copy-construction, and therefore we can now again copy-construct from unnamed temporaries!

All that is missing now is some glue to convert between GuardRef and Guard. We add this in form of a conversion operator and a converting constructor to Guard. Here is the complete code:

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
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
#include <iostream>
 
class Guard;
 
class GuardRef {
	friend class Guard;
private:
	int resource_;
private:
	GuardRef(int r)
		:resource_(r)
	{
		::std::cout << this << " GuardRef Constructor: " << resource_ << ::std::endl;
	}
public:
	GuardRef(GuardRef const& rhs)
		:resource_(rhs.resource_)
	{
		::std::cout << this << " GuardRef Copy Constructor: " << resource_ << ::std::endl;
	}
	~GuardRef()
	{
		::std::cout << this << " GuardRef Destructor" << ::std::endl;
	}
};
 
class Guard {
private:
	int resource_;
public:
	Guard(int r)
		:resource_(r)
	{
		::std::cout << this << " Guard Constructor" << ::std::endl;
		::std::cout << this << " *** Guarding " << resource_ << ::std::endl;
	}
	~Guard()
	{
		::std::cout << this << " Guard Destructor" << ::std::endl;
		if(resource_ > 0) {
			::std::cout << this << " *** Free " << resource_ << ::std::endl;
		}
	}
	Guard(Guard& rhs)
		:resource_(rhs.Detach())
	{
		::std::cout << this << " Copy constructor; Assuming ownership of " 
					<< resource_ << ::std::endl;
	}
	Guard(GuardRef const& ref)
		:resource_(ref.resource_)
	{
		::std::cout << this << " Constructing from GuardRef; Assuming ownership of " 
					<< resource_ << ::std::endl;
	}
	operator GuardRef()
	{
		::std::cout << this << " Converting to GuardRef" << ::std::endl;
		return GuardRef(Detach());
	}
private:
	int Detach()
	{
		::std::cout << this << " Detaching " << resource_ << ::std::endl;
		int ret = resource_;
		resource_ = 0;
		return ret;
	}
};
 
class Factory {
public:
	Guard BuildGuard()
	{
		return Guard(42);
	}
};
 
int main(int argc, char* argv[])
{
	{
		Factory f;
		Guard g(f.BuildGuard());
	}
	return 0;
}

Note how this approach is completely transparent to the user. The compiler is able to automatically deduce the required conversions to GuardRef and back, so the user will just use the factory method without knowing anything about the implementation magic taking place behind the curtains.

Let’s take a look at the output of that example program.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
0x7fffffffbbb0 Guard Constructor
0x7fffffffbbb0 *** Guarding 42
0x7fffffffbbb0 Converting to GuardRef
0x7fffffffbbb0 Detaching 42
0x7fffffffbba0 GuardRef Constructor: 42
0x7fffffffbc20 Constructing from GuardRef; Assuming ownership of 42
0x7fffffffbba0 GuardRef Destructor
0x7fffffffbbb0 Guard Destructor
0x7fffffffbc20 Converting to GuardRef
0x7fffffffbc20 Detaching 42
0x7fffffffbc10 GuardRef Constructor: 42
0x7fffffffbc00 Constructing from GuardRef; Assuming ownership of 42
0x7fffffffbc10 GuardRef Destructor
0x7fffffffbc20 Guard Destructor
0x7fffffffbc00 Guard Destructor
0x7fffffffbc00 *** Free 42

As you can see, we construct a total of three Guard objects and two GuardRefs. Apart from the Guard declared by the user (0x7fffffffbc00) they are all temporary. Your mileage may vary depending on your compiler’s ability to RVO.

In my case, the compiler first created the unnamed object from the return statement of Factory::BuildGuard (lines 1-2). This object is converted to a GuardRef, losing ownership of the resource in the process (l. 3-5). This GuardRef can now be used to construct the Guard that will actually be returned by the factory method (l. 6). After that, the function actually returns: The stack is unwound and both the temporary GuardRef as well as the original Guard are destroyed (l. 7-8). The new guard remains as return value on the stack.
However the return value is also just an unnamed temporary, so in order to assign it to the Guard object declared by the user, we need to perform the whole procedure once more: The unnamed return value is converted to a GuardRef (l. 9-11), which is used to construct the Guard declared by the user (l. 12). After that, both the temporary GuardRef and the returned object on the stack are destroyed (l.13-14), which effectively concludes the process. The final two lines were generated when the user’s guard object went out of scope and finally freed the resource again.

Let us conclude with a brief discussion of the approach. The bad news is that this is the only way to write a robust guard class with the discussed properties in the current C++-standard. The naive solution without GuardRef compiled without warnings on Microsoft’s C++ compiler due to RVO, but that does not change the fact that it is not valid code. GCC refused to compile because of the constructor type mismatch. Unfortunately, introducing the GuardRef will prevent any RVO from happening in both Microsoft’s and the GCC compiler, which is very unfortunate.

But then again, who cares? We can now succesfully apply the RAII idiom to arbitrary resources and the end-user will never have to bother with the implementation details. Sure, construction has just become a lot more complicated, but in the end GuardRef is a very light-weight object and will almost certainly stay that lightweight to all eternity. We could run into a problem if Guard was a complex proxy class with high construction costs. In such a case it would be mandatory to refactor the guarding aspect into a separate class, whose only responsible was guarding and nothing else (which is btw how a good design should have looked like in the first place).
Note that despite the high count of temporary objects, the underlying resource is still just allocated and released once. Since mere object construction/destruction is very cheap in C++, the whole overhead boils down to a couple of additional function calls, which is well justified given the increased comfort and safety to the user of such a class.

If this whole thing just caused you to shake your head in disbelief, don’t despair. This issue has been eliminated, among with a number of other peculiarities, by a feature of the upcoming C++0x standard called r-value references, which will be discussed in a future article.

Categories: Programming

Teamspeak 3 Server – Debian Startup Script

December 23rd, 2009 7 comments

In case you haven’t noticed: A few days ago the beta of TeamSpeak 3 was finally released.

At first glance, it seems to be a decent piece of software, which is more than you could say of its predecessor. The feature list is quite impressive and most of them seem to be well-thought-out.

One of the hurdles you’ll have to take when setting up a server yourself is the startup script. By now there are already countless user-made scripts flying around, but as you might’ve expected, that did not stop this author to write yet another one. This one avoids the grep/awk-voodoo of most scripts, instead using start-stop-daemon to get the job done.

As usual, this thing comes without any warranty whatsoever.

#!/bin/bash
#
#  Init script for TS3.
#  The server configuration will be written to the
#  SERVER_CONFIG_FILE .ini file on first start to avoid
#  display of server parameters in process listings; Thus
#  in order for changes to the config in this file to
#  be applied, stop the server, delete the .ini file
#  and run this script afterwards;
#  Do *not* apply config changes to the .ini directly!
#
 
## TS3 Config START
 
	# udp server port
	UDP_PORT=
 
	# number of virtual servers
	NUMBER_OF_SERVERS=1
 
	# additional options go here...
 
## TS3 Config END
 
# path to ts3 root directory
SERVER_PATH=<your_server_path_here>
# full path to ts3 server binary
SERVER_BINARY=$SERVER_PATH/<your_binary_name_here>
# user running ts3 server
TEAMSPEAK_SYSTEM_USER=<your_user_name_here>
# group running ts3 server
TEAMSPEAK_SYSTEM_GROUP=<your_group_name_here>
 
# server .ini config file
SERVER_CONFIG_FILE=ts3server.ini
 
# full path to pid file for start-stop-daemon
PID_FILE=$SERVER_PATH/server.pid
 
if [ -f $SERVER_CONFIG_FILE ]
then
	DAEMON_COMMAND_PARAMS="inifile=$SERVER_CONFIG_FILE"
else
	DAEMON_COMMAND_PARAMS="default_voice_port=$UDP_PORT \
				create_default_virtualserver=$NUMBER_OF_SERVERS \
				createinifile=1 \
				inifile=$SERVER_CONFIG_FILE"
fi						
 
case "$1" in
 start)
	echo "Starting TS3 server..."
	export LD_LIBRARY_PATH="${SERVER_PATH}:${LD_LIBRARY_PATH}"
	start-stop-daemon --start --quiet --exec "$SERVER_BINARY" --chdir "$SERVER_PATH" \
			  --chuid "$TEAMSPEAK_SYSTEM_USER" --group "$TEAMSPEAK_SYSTEM_GROUP" \
			  --background --make-pidfile --pidfile "$PID_FILE" \
			  $DAEMON_COMMAND_PARAMS
	if [ $? != 0 ]; then
		echo "! Failed. (Server already running?)"
		exit 1
	else
		echo "done."
	fi
 ;;
 stop)
 	echo "Stopping TS3 server..."
	start-stop-daemon --stop --quiet --pidfile "$PID_FILE"
	if [ $? != 0 ]; then
		echo "! Failed."
		exit 1
	else
		echo "done."
	fi
 ;;
 status)
	if [ -e $PID_FILE ]; then
		if ( kill -0 $(cat $PID_FILE) 2&gt; /dev/null ); then
			echo "Server is running"
		else
			echo "Server not running"
		fi
	else
		echo "Server PID file not found"
	fi
 ;;
 update-config)
 	echo "Deleting $SERVER_CONFIG_FILE..."
 	rm -f $SERVER_CONFIG_FILE
	$0 restart
 ;;
 restart)
	$0 stop && $0 start || exit 1
 ;;
 *)
	echo "Usage: $0 {start|stop|restart}"
    exit 1
 ;;
esac
 
exit 0

Update: Added export call for Beta17.

Categories: IT