Re: [rust-dev] [ANN] Rust ported to DragonFlyBSD

2014-07-30 Thread Michael Neumann



Am 29.07.2014 um 20:37 schrieb Rob Latham:
 After trying to cross-compile Rust by specifying --target
 x86_64-pc-dragonfly-elf to Rust’s own configure script and spending
 numerous hours just to note that the build fails...

 Howdy, fellow crazy cross-compiling person.  Did you by any chance
 come across my message from a week or so ago?  One response seemed
 likely to help you if you were encountering a specific kind of build
 failure:

 https://mail.mozilla.org/pipermail/rust-dev/2014-July/010827.html

 what other errors were you encountering with the --target approach?

When building the related C libraries you also need to specify the
--sysroot to point to the DragonFly tree, otherwise it's building the
libraries targeted at DragonFly but with Linux header files, which
clearly is *wrong*. Actually I wasn't able to cross-compile LLVM. Also
when using the --target approach, I always had to wait for hours until
it finished the Linux (host) build before it started to build the
target. I think I was just waiting too much time for compiles to finish.
If someone else figures out how to cross-compile to DragonFly with the
--target approach I am happy to know :).

Regards,

  Michael
___
Rust-dev mailing list
Rust-dev@mozilla.org
https://mail.mozilla.org/listinfo/rust-dev


Re: [rust-dev] [ANN] Rust ported to DragonFlyBSD

2014-07-30 Thread Michael Neumann



Am 30.07.2014 um 16:04 schrieb Rob Latham:
 On Wed, Jul 30, 2014 at 8:44 AM, Michael Neumann mneum...@ntecs.de 
wrote:

 Am 29.07.2014 um 20:37 schrieb Rob Latham:
 what other errors were you encountering with the --target approach?

 When building the related C libraries you also need to specify the
 --sysroot to point to the DragonFly tree, otherwise it's building the
 libraries targeted at DragonFly but with Linux header files, which
 clearly is *wrong*.

 I'd set this up in mk/platform.mk.  Check out how arm-apple-ios does it:

 CFG_IOS_SDK = $(shell xcrun --show-sdk-path -sdk iphoneos 2/dev/null)
 CFG_IOS_FLAGS = -target armv7-apple-darwin -isysroot $(CFG_IOS_SDK)
 -mios-version-min=7.0
 CFG_CFLAGS_arm-apple-ios := -arch armv7 -mfpu=vfp3 $(CFG_IOS_FLAGS)

 https://github.com/rust-lang/rust/blob/master/mk/platform.mk#L158

I tried this as you can see here [1]. But you have to consider that Mac
OS X comes with an iphone SDK while Linux does not come with DragonFly
SDK :D. I think no-one ever tried to cross-compile a program for
DragonFly :).

[1]: 
https://github.com/mneumann/rust/commit/ab1124980f97558af87b789a1c0772bfa7e23704 



Regards,

  Michael
___
Rust-dev mailing list
Rust-dev@mozilla.org
https://mail.mozilla.org/listinfo/rust-dev


[rust-dev] [ANN] Rust ported to DragonFlyBSD

2014-07-29 Thread Michael Neumann

Hi all,

I am happy to announce that I succeeded in porting Rust to the DragonFly
operating system. [This article][1] describes `how` and might also be of
interest to others porting Rust to NetBSD or OpenBSD. Within the next
week I submit patches to the LLVM project (segmented stack support for
DragonFly) and also to the rust repo itself. My `dragonfly` branch of
the Rust repository can be found [here][2].

If someone is interested to try out early, I can provide some binaries
until I set up some automatic builds.

Regards,

  Michael

[1]: http://www.ntecs.de/blog/2014/07/29/rust-ported-to-dragonflybsd/
[2]: https://github.com/mneumann/rust/tree/dragonfly
___
Rust-dev mailing list
Rust-dev@mozilla.org
https://mail.mozilla.org/listinfo/rust-dev


Re: [rust-dev] PipeStream.by_ref() - Multiple applicable methods problem

2014-04-30 Thread Michael Neumann



Am 29.04.2014 22:51, schrieb Alex Crichton:
 The by_ref() method exists on both the Reader and the Writer trait,
 and you're working with a stream which implements both Reader and
 Writer (hence the confusion by the compiler).

 You could work around it with something like:

  fn rdr'a, T: Reader(t: 'a mut T) - RefReader'a, T {
  t.by_ref()
  }

 Eventually, with UFCS, you'll be able to do something like:

  let rdr = Reader::by_ref(mut inp);

 (hopefully soon!)

Thanks so much!  This works!

Actually I was trying to explicitly specify the type as in:

  let rdr: RefReaderPipeStream = t.by_ref();

and was wondering why it failed.

Regards,

  Michael
___
Rust-dev mailing list
Rust-dev@mozilla.org
https://mail.mozilla.org/listinfo/rust-dev


[rust-dev] PipeStream.by_ref() - Multiple applicable methods problem

2014-04-29 Thread Michael Neumann

Hi,

I don't know how to figure out calling by_ref() for a PipeStream:

use std::io::Process;
use std::io::BufferedReader;

fn main() {

  let mut child = match Process::new(/usr/bin/xzcat,
 [test.log.xz.to_owned()]) {
Ok(child) = child,
Err(e) = fail!(failed to execute child: {}, e),
  };

  let inp = child.stdout.get_mut_ref();
  // ERROR occurs here
  let mut rdr = BufferedReader::new(inp.by_ref());

  for line in rdr.lines() {
print!({}, line.unwrap());
  }

  assert!(child.wait().success());
}


This is the error output:

test.rs:13:37: 13:49 error: multiple applicable methods in scope
test.rs:13   let mut rdr = BufferedReader::new(inp.by_ref());
   ^~~~
test.rs:13:37: 13:49 note: candidate #1 is `std::io::Writer::by_ref`
test.rs:13   let mut rdr = BufferedReader::new(inp.by_ref());
   ^~~~
test.rs:13:37: 13:49 note: candidate #2 is `std::io::Reader::by_ref`
test.rs:13   let mut rdr = BufferedReader::new(inp.by_ref());
   ^~~~
test.rs:13:17: 13:36 error: failed to find an implementation of trait 
std::io::Reader for std::io::RefWriter,std::io::pipe::PipeStream

test.rs:13   let mut rdr = BufferedReader::new(inp.by_ref());
   ^~~


Any hints?

Actually what I want to accomplish is to iterate line by line over a
PipeStream.

Regards,

  Michael
___
Rust-dev mailing list
Rust-dev@mozilla.org
https://mail.mozilla.org/listinfo/rust-dev


Re: [rust-dev] About RFC: A 30 minute introduction to Rust

2014-03-05 Thread Michael Neumann



Am 05.03.2014 03:54, schrieb Fernando Pelliccioni:

 So, now, what is the difference between...

 // rust
 let i = ~1234;

 and

 // C++
 auto i = make_uniqueint(1234);

 ?

 The Rust code is shorter, but perhaps, more illegible. I think it is
 matter of taste.

 But now, the real advantage is not as great as before, or not?

Except that Rust will catch use-after-move at compile time, while C++
will segfault at runtime.

Try something like this:

let i = ~1234;
let j = i; // i moves into j
println!({}, *j); // this is OK
println!({}, *i); // tries to print `i` . Compile ERROR

This will not compile in Rust!

Try the same in C++:

auto i = make_uniqueint(1234);
auto j = std::move(i);
cout  *j  endl; // 1234
cout  *i  endl; // Segmentation Fault

Maybe there are warnings generated by C++ which detect this
use-after-move... the point is that unique pointers in C++ are more a
library add-on rather than built into the language.

 I think there is a bad intension of the author of the article to enlarge
 the advantage.


 Question, How to write the following in Rust using the operator ~ ?

 auto e = make_uniqueEmployee(Peter);

In Rust this will be:

let e = ~Employee {name: ~Peter};

 ...and, what about shared-ownership?

I am not using shared ownership very often, but this should work:

let e = @Employee {name: ~Peter};

But I think this will change towards using either GcEmployee or
RcEmployee so you have the choice between reference counting and
(thread local) garbage collection.

 If the author informs all this, I would think that there is no bad
 intention, but he doesn't, and he uses the ugliest C++ code possible.

You interpret this as bad intention but I am sure there was no bad
intention involved by the author of the article. It's always difficult
to show off the advantages of new languages without hurting the feelings
of users of the old language.

I love both Rust and C++, but for C++ this is more a love-hate
relationship :)

Regards,

  Michael
___
Rust-dev mailing list
Rust-dev@mozilla.org
https://mail.mozilla.org/listinfo/rust-dev


Re: [rust-dev] reader.lines() swallows io errors

2014-02-19 Thread Michael Neumann


Am 19.02.2014 08:52, schrieb Phil Dawes:
Is that not a big problem for production code? I think I'd prefer the 
default case to be to crash the task than deal with a logic bug.


The existence of library functions that swallow errors makes reviewing 
code and reasoning about failure cases a lot more difficult.


This is why I proposed a FailureReader: 
https://github.com/mozilla/rust/issues/12368


Regards,

Michael
___
Rust-dev mailing list
Rust-dev@mozilla.org
https://mail.mozilla.org/listinfo/rust-dev


Re: [rust-dev] redis-rs Pipelining and Connections

2014-01-19 Thread Michael Neumann


Am 19.01.2014 21:58, schrieb Armin Ronacher:

Hi,

I'm currently wrapping all of redis in a fairly high-level library 
similar to the Python binding.  It's currently living here:

  https://github.com/mitsuhiko/redis-rs


Cool, another redis library :). This is mine: [1]



In general I did not encounter many problems with that but there are 
some open questions in regards to how pipelining and connection 
pooling should work.


In general, this is roughly how the library works:

  extern mod redis;

  fn main() {
let client = redis::Client::open(redis://127.0.0.1/).unwrap();
let mut con = client.get_connection().unwrap();
println!(Got value: {}, con.get(my_key).unwrap_or(no value));
  }

Pipelining:

I currently have no idea how to implement this.  The API I had in mind 
was this:


  let mut con = client.get_connection().unwrap();
  let mut counter, data;
  con.pipeline()
.incr(counter).tap(|value| { counter = value; })
.get(data_key).tap(|value| { data = value; })
.execute();

The general idea is pretty simple: whereas a regular redis connection 
immediately returns the results the pipeline buffers them up and will 
execute the tap'ed callbacks to return the data. Unfortunately I have 
no idea how this can be implemented currently.  There are two issues 
with that:  first of all I don't fancy implementing all methods twice 
(once for the connection and once for the pipeline), secondly the 
.tap() method needs to change signature depending on the return value 
of the most recent operation.


I think, if you add something like Postpone(mut Connection) to the 
Value type it could work.
Method tap would only be defined for type Value and will fails it it's 
value is not Postpone.

Something like that:

enum Value {
  Nil,
  Int(int64),
  Data(~[u8]),
  Error(~str),
  Status(~str),
  Postpone(mut Connection)
}

impl Value {
  fn tap(self, fn callback) - Connection {
 match *self {
 Postpone(conn) = { conn.add_callback(callback); conn }
 _ = fail!()
}
  }
}

Of course incr() etc. will only return Postpone if it is in pipeline 
mode, otherwise it will execute

normally and return the redis value.

Lastly because the pipeline borrows the connection as mutable the code 
currently would need to be placed in a separate scope, otherwise the 
con object becomes unusable after the pipeline call.


Connections:

I don't know what the best way to deal with connections is.  Right now 
I have a client object which tries to connect to redis and does the 
address resolution. The actual connection however is provided by a 
get_connection() function on it which will connect and return a 
connection object.  This way two tasks can have a connection each.  I 
was thinking of extending this with a connection pool but I'm not sure 
how to do this properly since I don't want that the client needs to be 
mutable to get a connection.  That would make it much harder to use 
with multiple tasks.


Hm, in my rust-redis library, I just connect in redis::Client::new(). 
That's pretty simple. What's the problem if each task just calls 
Client::new() instead of get_connection()? If address resolution is your 
problem, I'd solve it differently.


Regards,

  Michael

[1]: https://github.com/mneumann/rust-redis

___
Rust-dev mailing list
Rust-dev@mozilla.org
https://mail.mozilla.org/listinfo/rust-dev


[rust-dev] ASCII character literals

2014-01-15 Thread Michael Neumann

Hi,

There are lots of protocols based on ASCII character representation. In 
Rust, the natural way to represent them is

by an u8 literal (optionally wrapped within std::ascii::Ascii).
What I am missing is a simple way to represent those literals in code. 
What I am doing most of the time is:


fn read_char() - Optionchar {
   match io.read_byte() {
 Some(b) = Some(b as char),
 None = None
  }
}

And then use character literals in pattern matching. What I'd highly 
prefer is a way to directly repesent ASCII characters

in the code, like:

match io.read_byte().unwrap {
'c'_ascii = 
   
}

If macros would work in patterns, something like:

   match ... {
   ascii!('a') = ...
   }

would work for me too. Ideally that would work with range patterns as 
well, but of course an ascii_range!() macro would

do the same.

Is this useful to anyone?

Regards,

Michael
___
Rust-dev mailing list
Rust-dev@mozilla.org
https://mail.mozilla.org/listinfo/rust-dev


Re: [rust-dev] RFC: Future of the Build System

2014-01-11 Thread Michael Neumann
rustc is just another regular Rust application. So use the tools that 
any other Rust application (will) use ;-)


I think at some point in time there will be a capable build tool written 
in Rust (like there is for all the other languages). Then it would make

sense to switch using it for the compiler as well.

Michael

Am 11.01.2014 08:56, schrieb George Makrydakis:

There is little reason to believe that having a build system in Rust would make 
It harder for people to package.

I do understand the predependecy argument, but the Rust compiler itself in 
order to compile has predependencies anyway, as does any similar project. 
Therefore the decisional weight of choosing a non - rust based solution over a 
rust one because Debian packagers have problems packaging a compiler is not 
adequately justified.

Using a well known build system as a means to appeal to programmers is 
seemingly an advantage, but it does not exonerate them from having to be 
competent in Rust before they write useful programs. And that has a learning 
curve superior to that of a build system.

As for boost's jam I have nothing to say other than boost having its own build 
system makes it easy for boost first; this does not mean that their needs are 
those of everybody else and boost is a library, not a programming language 
itself. So, again, a decision based on picking a popular solution on the basis 
of such a comparison, has flawed background.

Lastly, imagine the irony of Rust proposing to use python, c, c++ based build 
tools for simple packages. That would make packagers more frustrated because of 
a wider set of dependecies. While end users would have to also deal with a 
known system, its eventual inadequacies could not be met directly by Rust devs 
unless they start amending that system in order to deal with them. Therefore, 
maintenance overhead is inescapable either way, with the pessimization of 
relying in another nom - Rust project in order to make it worth your while to 
enjoy programming in Rust.

The only valid argument against having a build system proposed as the official, 
defacto, cross - platform way of building rust packages written in rust is its 
development and maintenance overhead for the rust core team itself.

That problem is easily circumvented by not proposing one right now and letting 
it to the end developer decide. If however an official build system is to be 
proposed, Rust developers merit having it done on their own platform, thus 
proving rust's worth. It is 2014 after all.

G.



Lee Braiden leebr...@gmail.com wrote:

On 10/01/14 08:16, Gaetan wrote:

I am not in favor of a customized build system. For instance boost
library use their jam build system, and i never figured how to use it
in my projects.

I push to use standard and well proved build system like cmake or
scons, at least for major components. This would give a nice example
of how to use it in any projects.


I'd agree with that on both counts: the principle of using something
standard, and the two recommendations.

CMake would probably get my vote, because it's not so much a build
tool,
as a meta tool for whichever system you prefer, so it would fit in well

with various platform-specific IDEs, unusual platforms (android,
embedded, ...), etc.  That said, scons is also a strong contender, and
which of the two is more open to integrating patches and working with
new languages is very much worth considering.

I think Rust will be contributing to the wider community by lending its

support (and patches) to a common, modern build system, AND it will get

something back in terms of users who already know the build system.



 On Friday, January 10, 2014, George Makrydakis wrote:


 Hello,

 Having a build system entirely dependent of Rust alone, would
 make the entire experience in deploying the language

extremely

 cohere. The only counter - argument is indeed that it would
 require some work to get this to fruition. I would like to
 know if this has any chance of getting priority soon enough.


Bear in mind that Debian are having a lot of issues packaging Rust
already, because it self-compiles.  If the build tool also had a Rust
pre-dependency, that would be a big step backwards.

___
Rust-dev mailing list
Rust-dev@mozilla.org
https://mail.mozilla.org/listinfo/rust-dev


___
Rust-dev mailing list
Rust-dev@mozilla.org
https://mail.mozilla.org/listinfo/rust-dev


[rust-dev] Porting rust to DragonFlyBSD

2014-01-07 Thread Michael Neumann

Hi there,

At the moment rust only supports Linux/FreeBSD/Windows/MacOSX. I'd 
like to be

able to compile it on DragonFlyBSD [1].

I am trying to get the FreeBSD stage0/bin/rustc to run on DragonFly, yet 
with no success.
Is it possible to generate a static rustc binary somehow? Or what in 
general is the procedure

to port rustc to a different platform?

Regards,

Michael

[1]: http://www.dragonflybsd.org/
___
Rust-dev mailing list
Rust-dev@mozilla.org
https://mail.mozilla.org/listinfo/rust-dev


[rust-dev] [ANN] rust-toml - TOML configuration file parser

2014-01-06 Thread Michael Neumann

Hi all,

rust-toml [1] is TOML [2] configuration file parser :)

Regards,

   Michael

[1]: https://github.com/mneumann/rust-toml
[2]: https://github.com/mojombo/toml
___
Rust-dev mailing list
Rust-dev@mozilla.org
https://mail.mozilla.org/listinfo/rust-dev


Re: [rust-dev] Configuration files library for Rust

2014-01-05 Thread Michael Neumann


Am 04.01.2014 15:01, schrieb Flaper87:

Hi Guys,

I was looking around and I couldn't find a config file parser library 
for Rust. Getopt support seems to be pretty complete and stable, which 
would make the development of such library easier.


There is now a TOML parser for Rust [1] :)

[1]: https://github.com/mneumann/rust-toml

Regards,

Michael
___
Rust-dev mailing list
Rust-dev@mozilla.org
https://mail.mozilla.org/listinfo/rust-dev


[rust-dev] [ANN] rust-redis and rust-msgpack

2014-01-04 Thread Michael Neumann

Hi all,

rust-redis: A Redis client library written in pure Rust. Thanks to the 
new rust runtime

it is pretty fast, despite being only 200 lines of code.

rust-msgpack: Fully featured and high performance msgpack implementation 
for Rust.


Both work with rust 0.9-pre.

Regards,

  Michael
___
Rust-dev mailing list
Rust-dev@mozilla.org
https://mail.mozilla.org/listinfo/rust-dev


Re: [rust-dev] [ANN] rust-redis and rust-msgpack

2014-01-04 Thread Michael Neumann


Am 04.01.2014 17:14, schrieb Michael Neumann:

Hi all,

rust-redis: A Redis client library written in pure Rust. Thanks to the 
new rust runtime

it is pretty fast, despite being only 200 lines of code.

rust-msgpack: Fully featured and high performance msgpack 
implementation for Rust.


Both work with rust 0.9-pre.


Too stupid/sleepy that I forgot the links:

http://github.com/mneumann/rust-redis
http://github.com/mneumann/rust-msgpack

Regards,

  Michael
___
Rust-dev mailing list
Rust-dev@mozilla.org
https://mail.mozilla.org/listinfo/rust-dev


Re: [rust-dev] Configuration files library for Rust

2014-01-04 Thread Michael Neumann


Am 04.01.2014 18:38, schrieb Corey Richardson:

oslo.config looks decent. On some projects I've worked on, we started
out using INI files but found them severely lacking once we wanted to
extend the options. We ended up using libconfig[0], which I think is
an excellent library. In multibuilder[1], we use extra::serialize to
load a config directly into the struct we'll be using. It's super
convenient, but a bit unfortunate in that it's impossible to make a
field truly optional (OptionT requires the field to be null, iirc).

[0] http://www.hyperrealm.com/libconfig/
[1] https://github.com/huonw/multibuilder/blob/master/main.rs#L68


There is also TOML [1], an extended version of the INI config file format,
which is used by a variety of languages.

[1]: https://github.com/mojombo/toml

Regards,

  Michael

___
Rust-dev mailing list
Rust-dev@mozilla.org
https://mail.mozilla.org/listinfo/rust-dev


Re: [rust-dev] Configuration files library for Rust

2014-01-04 Thread Michael Neumann


Am 04.01.2014 21:30, schrieb Tony Arcieri:
On Sat, Jan 4, 2014 at 12:26 PM, Gaetan gae...@xeberon.net 
mailto:gae...@xeberon.net wrote:


I m interessed on having your feedback on json and yaml vs toml
for instance.

JSON is ugly and token-ridden for configuration files. Having worked 
with tools that use it for this purpose, I find the configuration hard 
to read. Then there's the issue of comments, which are particularly 
important for configuration files. Some things have adopted JS-style 
comments for this purpose, but that's technically not standard JSON.


YAML's problem is indentation errors can turn into configuration 
errors, and they're incredibly tricky to spot. I've run into cases 
where we didn't spot problems until we deployed to production because 
the production section of a configuration file was misindented.


And, I think it's pretty hard to write a YAML parser. The spec is pretty 
extensive. Whereas a TOML or INI parser, you can hack within a few hours.


Regards,

  Michael
___
Rust-dev mailing list
Rust-dev@mozilla.org
https://mail.mozilla.org/listinfo/rust-dev


Re: [rust-dev] Static initialisation of LinearMap

2013-07-02 Thread Michael Neumann

Am 02.07.2013 17:29, schrieb Alex Crichton:

I was looking for something like: static h:HashMapK,C =
{(K,V),(K,V).}.
Is this possible at all?


What would be much easier is to use a sorted array and binary search for 
lookup.
But sorting at compile time seams to be tricky, for simple values ok, 
but for more

complex keys I think it's impossible.

Regards,

  Michael
___
Rust-dev mailing list
Rust-dev@mozilla.org
https://mail.mozilla.org/listinfo/rust-dev


Re: [rust-dev] RFC: Explicit stack switching

2013-02-02 Thread Michael Neumann

Am 02.02.2013 10:16, schrieb Patrick Walton:

On 2/1/13 11:02 PM, Brian Anderson wrote:

In the library we add this sort of function that simply guarantee that
the closure has some amount of stack available.

do reserve_stack(Standard) { rust_task_fail(); }
do reserve_stack(Tiny) {... }
do reserve_stack(Large) { }
do reserve_stack(Size(4096)) { }


My main worry about this is that it's always guesswork. Determining 
how much stack a C function needs is really hard and involves doing a 
lot of non-local reasoning. Getting it wrong can result in exploitable 
security vulnerabilities. From a safety POV, it seems that you always 
really want as big a stack as possible, unless the function is 
something trivial like floor().


Ultimately we never often want a stack to be increased in size as this 
seems to be a quite expensive operation. Calling a function that crosses 
stack space
boundaries (i.e. when it has to alloc new stack space) inside a loop 
might severly affect performance. do reserve_stack could be used to 
prevent that, but
the programmer need to be aware of that. At least theoretical it should 
be possible to calculate how much stack space a given function needs 
including
all the space that all called functions need. Recursive functions would 
result in unlimited stack space, just because we cannot analyse the 
depths of
the calls. But for most of the code, we would know the maximum stack 
space used. We could use this when we start new tasks to allocate a 
contiguous
stack large enough to hold the whole computation of that task without 
the need to resize (in which case we could optimize away the checks in front

of each function).

Most functions called by FFI should have a pretty flat call hierarchy. 
At least functions in lib_c do have. Ideally there is information at 
link time how much
space a given function consumes (I read something about this topic on 
LLVM segmented stacks). If not, then it is always a guess and it might 
be better
to perform those calls only inside a special task and make sure this 
task has enough space and that it is protected against stack overflowing 
(don't have

native threads a guard page after the stack segment?).

Michael
___
Rust-dev mailing list
Rust-dev@mozilla.org
https://mail.mozilla.org/listinfo/rust-dev


Re: [rust-dev] Misc questions

2013-02-01 Thread Michael Neumann

Am 30.01.2013 00:43, schrieb Brian Anderson:

On 01/29/2013 04:47 AM, Michael Neumann wrote:

Am 29.01.2013 03:01, schrieb Brian Anderson:

On 01/28/2013 05:29 PM, Graydon Hoare wrote:

On 13-01-28 04:56 PM, Brian Anderson wrote:

I think libuv is doing too much here. For example, if I don't 
want to

remove the socket from the event
queue, just disable the callback, then this is not possible. I'd
prefer when I could just tell libuv that
I am interested in event X (on Windows: I/O completion, on UNIX: I/O
availability).

Yet the optimization you suggest has to do with recycling the buffer,
not listening for one kind of event vs. another.

In general I'm not interested in trying to get underneath the
abstraction uv is providing. It's providing an IOCP-oriented 
interface,

I would like to code to that and make the rust IO library not have to
worry when it's on windows vs. unix. That's the point of the 
abstraction
uv provides, and it's valuable. If it means bouncing off epoll a 
few too
many times (or reallocating a buffer a few too many times), I'm not 
too

concerned. Those should both be O(1) operations.

Is it possible to do this optimization later or do we need to plan 
for
this ahead of time? I would prefer to use the uv API as it's 
presented

to start with.

The optimization to use a caller-provided buffer should (a) not be
necessary to get us started and (b) be equally possible on either
platform, unix or windows, _so long as_ we're actually sleeping a task
during its period of interest in IO (either the pre-readiness sleep 
or a

post-issue, pre-completion sleep). In other words, if we're simulating
sync IO, then we can use a task-local buffer. If we're _not_ 
simulating

sync IO (I sure hope we do!) then we should let uv allocate and free
dynamic buffers as it needs them.

But I really hope we wind up structuring it so it simulates sync IO.
We're providing a task abstraction. Users _want_ the sync IO 
abstraction

the same way they want the sequential control flow abstraction.


Presenting the scheduler-originating I/O as synchronous is what I 
intend. I am not sure that we can guarantee that a task is actually 
waiting for I/O when an I/O event occurs that that task is waiting 
for. A task may block on some other unrelated event while the event 
loop is doing I/O. Pseudocode:


let port = IOPort::connect(); // Assume we're doing I/O reads using 
something portlike

while port.recv() {
// Block on a different port, while uv continues doing I/O on 
our behalf

let intermediate_value = some_other_port.recv();
}

This is why I'm imagining that the scheduler will sometimes need to 
buffer.


I don't think so. Let me explain.

This anyway is only a problem (which can be solved) iff we want to be 
able to treat I/O like a
port and want to wait for either one to resume our thread. And I 
assume we want this, so
that we can listen on an I/O socket AND for example for incoming 
messages at the same time.


The kernel provides a way to do (task-local) blocking I/O operations. 
There is no way for the
task to return from a read() call unless data comes in or in case of 
EOF (or any other error
condition).This behaves basically like a blocking POSIX read() call, 
just that it is converted
into asynchronous read by libuv under the hood. To expose I/O as 
port, we have to start

a new task:

  let fd = open(...);
  let (po, ch) = streams::pipe();
  do task::spawn {
loop {
  let buf: ~[u8] = vec::from_fn(1000, || 0);
  let nread = fd.read(buf, 1000);
  if nread  0 {
ch.send(Data(buf))
  }
  else if nread == 0 {
ch.send(EOF)
  }
  else {
ch.send(Error)
  }
}
  }


Yes, a single call to 'read' will not return until some I/O arrives, 
but after 'read' returns I/O continues to arrive and that I/O needs to 
be stored somewhere if the task doesn't immediately block in another 
call to 'read' on that same fd. Taking the above example:


loop {
// This will block until data arrives at which point the task will 
be context-switched in and the data returned.

let nread = fd.read(buf, 1000);

// This will put the task to sleep waiting on a message on cmd_port
let command = cmd_port.recv();
}

Until data arrives on cmd_port the task cannot be scheduled. While the 
task is asleep the I/O loop can't be blocked since other tasks are 
using it too. So in the meantime uv continues to receive data from the 
open fd and it needs to live somewhere until the task calls 'read' 
again on the same fd. Perhaps there's something I don't understand 
about the uv API here, but I think that once we start reading uv is 
going to continually provide us with data whether we are ready for it 
or not.




  // now we can treat `po` as a Port and call select() on it


But I don't think channel I/O will be used that often.

Note that one big advantage is that we can specify the buffer size 
ourself!

When we would let libuv create a  buffer for us, how would

Re: [rust-dev] Misc questions

2013-01-29 Thread Michael Neumann

Am 29.01.2013 03:01, schrieb Brian Anderson:

On 01/28/2013 05:29 PM, Graydon Hoare wrote:

On 13-01-28 04:56 PM, Brian Anderson wrote:


I think libuv is doing too much here. For example, if I don't want to
remove the socket from the event
queue, just disable the callback, then this is not possible. I'd
prefer when I could just tell libuv that
I am interested in event X (on Windows: I/O completion, on UNIX: I/O
availability).

Yet the optimization you suggest has to do with recycling the buffer,
not listening for one kind of event vs. another.

In general I'm not interested in trying to get underneath the
abstraction uv is providing. It's providing an IOCP-oriented interface,
I would like to code to that and make the rust IO library not have to
worry when it's on windows vs. unix. That's the point of the abstraction
uv provides, and it's valuable. If it means bouncing off epoll a few too
many times (or reallocating a buffer a few too many times), I'm not too
concerned. Those should both be O(1) operations.


Is it possible to do this optimization later or do we need to plan for
this ahead of time? I would prefer to use the uv API as it's presented
to start with.

The optimization to use a caller-provided buffer should (a) not be
necessary to get us started and (b) be equally possible on either
platform, unix or windows, _so long as_ we're actually sleeping a task
during its period of interest in IO (either the pre-readiness sleep or a
post-issue, pre-completion sleep). In other words, if we're simulating
sync IO, then we can use a task-local buffer. If we're _not_ simulating
sync IO (I sure hope we do!) then we should let uv allocate and free
dynamic buffers as it needs them.

But I really hope we wind up structuring it so it simulates sync IO.
We're providing a task abstraction. Users _want_ the sync IO abstraction
the same way they want the sequential control flow abstraction.


Presenting the scheduler-originating I/O as synchronous is what I 
intend. I am not sure that we can guarantee that a task is actually 
waiting for I/O when an I/O event occurs that that task is waiting 
for. A task may block on some other unrelated event while the event 
loop is doing I/O. Pseudocode:


let port = IOPort::connect(); // Assume we're doing I/O reads using 
something portlike

while port.recv() {
// Block on a different port, while uv continues doing I/O on our 
behalf

let intermediate_value = some_other_port.recv();
}

This is why I'm imagining that the scheduler will sometimes need to 
buffer.


I don't think so. Let me explain.

This anyway is only a problem (which can be solved) iff we want to be 
able to treat I/O like a
port and want to wait for either one to resume our thread. And I assume 
we want this, so
that we can listen on an I/O socket AND for example for incoming 
messages at the same time.


The kernel provides a way to do (task-local) blocking I/O operations. 
There is no way for the
task to return from a read() call unless data comes in or in case of EOF 
(or any other error
condition). This behaves basically like a blocking POSIX read() call, 
just that it is converted
into asynchronous read by libuv under the hood. To expose I/O as port, 
we have to start

a new task:

  let fd = open(...);
  let (po, ch) = streams::pipe();
  do task::spawn {
loop {
  let buf: ~[u8] = vec::from_fn(1000, || 0);
  let nread = fd.read(buf, 1000);
  if nread  0 {
ch.send(Data(buf))
  }
  else if nread == 0 {
ch.send(EOF)
  }
  else {
ch.send(Error)
  }
}
  }

  // now we can treat `po` as a Port and call select() on it


But I don't think channel I/O will be used that often.

Note that one big advantage is that we can specify the buffer size ourself!
When we would let libuv create a  buffer for us, how would it know the
buffer size? The alloc_cb you provide to libuv upon uv_start_read() will get
a suggested_size parameter passed, but this is 64k by default, and libuv
cannot know what kind of I/O protocol you are handling. When I do
line oriented I/O, I would not need a full 64k buffer allocated for every
read, which in the worst case would only return one byte in it in case
of a very slow sender (send one byte each second). Or is 64k enough
for receiving a very large packet. We clearly want a way to tell the I/O
system how large we expect the packet to be that will arrive over I/O
otherwise this is completely useless IMHO.

We would still have one separate iotask per scheduler. This is a native
thread and runs the I/O loop. There is no way to do that inside the
scheduler as we would block any task while waiting for I/O.
The callbacks like on_read_cb would simply notify the scheduler
that the task that was responsible for doing this read operation
can now resume. As the scheduler lives in another thread
(the thread in which all tasks of that scheduler live in)
and might be active, we need to do some locking here.
When the scheduler gets 

Re: [rust-dev] Misc questions

2013-01-29 Thread Michael Neumann

Am 29.01.2013 02:29, schrieb Graydon Hoare:

On 13-01-28 04:56 PM, Brian Anderson wrote:


I think libuv is doing too much here. For example, if I don't want to
remove the socket from the event
queue, just disable the callback, then this is not possible. I'd
prefer when I could just tell libuv that
I am interested in event X (on Windows: I/O completion, on UNIX: I/O
availability).

Yet the optimization you suggest has to do with recycling the buffer,
not listening for one kind of event vs. another.

In general I'm not interested in trying to get underneath the
abstraction uv is providing. It's providing an IOCP-oriented interface,
I would like to code to that and make the rust IO library not have to
worry when it's on windows vs. unix. That's the point of the abstraction
uv provides, and it's valuable. If it means bouncing off epoll a few too
many times (or reallocating a buffer a few too many times), I'm not too
concerned. Those should both be O(1) operations.


I think allocating a buffer performs much better than waking up the 
event loop for
every read, because waking up the event loop involves kernel activity on 
both

scheduler and iotask, while malloc should in most cases be pure user-level.
And allocating buffers allows us to asynchronously continue reading 
while the task
is still doing some computations. If we would allow multiple readers on 
a single port
(do we? I think channels in Go allow that), then we would even have a 
very simple way
to load balance I/O to multiple tasks. This could actually make sense in 
many scenarios.
Kind of work-stealing. And we could build arbitrary pipelines. Of course 
we can
simulate the same by using a dispatcher task, but this would incur some 
overhead.



Is it possible to do this optimization later or do we need to plan for
this ahead of time? I would prefer to use the uv API as it's presented
to start with.

The optimization to use a caller-provided buffer should (a) not be
necessary to get us started and (b) be equally possible on either
platform, unix or windows, _so long as_ we're actually sleeping a task
during its period of interest in IO (either the pre-readiness sleep or a
post-issue, pre-completion sleep). In other words, if we're simulating
sync IO, then we can use a task-local buffer. If we're _not_ simulating
sync IO (I sure hope we do!) then we should let uv allocate and free
dynamic buffers as it needs them.


We are kind of simulating sync IO by using a channel. But IO would be 
async in the

background (if we do not want to wakup the event loop for every read), so we
would need buffers.


But I really hope we wind up structuring it so it simulates sync IO.
We're providing a task abstraction. Users _want_ the sync IO abstraction
the same way they want the sequential control flow abstraction.


Yes. I (now) fully agree.


(Indeed, on an appropriately-behaving system I fully expect task=thread
and sync IO calls=system calls)


If using a SizedChannel(1) each io.recv would correspond to one read() 
syscall, except
that the syscall could have happend long ago. Channels with longer 
queues would mean

that up to n (size of queue) read() calls could have happend.

Regards,

  Michael
___
Rust-dev mailing list
Rust-dev@mozilla.org
https://mail.mozilla.org/listinfo/rust-dev


Re: [rust-dev] Misc questions

2013-01-29 Thread Michael Neumann

Am 29.01.2013 01:56, schrieb Brian Anderson:

On 01/28/2013 03:37 PM, Michael Neumann wrote:

Am 28.01.2013 22:46, schrieb Brian Anderson:

On 01/26/2013 04:07 AM, Michael Neumann wrote:

Am 26.01.2013 13:01, schrieb Michael Neumann:

Am 26.01.2013 12:28, schrieb Michael Neumann:
Another question: When a task sends a message to another task, 
and this task is waiting exactly for this event, will it directly 
switch to that task, or will it buffer the message?
Sometimes this could be quite handy and efficient. I rember this 
was done in the L4 microkernel (www.l4ka.org), which only allowed 
synchronous IPC. It could make sense to provide a
send_and_receive directive, which sends to the channel and lets 
the scheduler know that it is now waiting for a message to 
receive from another port. So send_and_receive could
directly switch to the other task, and when this does a send back 
to the calling task, it will switch back to it. If you don't have 
send_and_receive as atomic operation, there
is no way to switch back to the other task, as it might still be 
running.


as it might still be running is here of course wrong (as we 
switched to another thread). What I wanted to say is, that it is 
not waiting for any event, so it is not in a blocking state, so that

we cannot directly switch back (matching the recv() and the send()).

Ideally the task that wants to read would do the non-blocking I/O 
itself, and the scheduler would just notify when it can read. 
But I think this is not possible with libuv as you
have no control over when to read (except using uv_read_start() / 
_stop). I think this would be much more efficient and even more 
powerful (one can read directly into a buffer...
there is no need to allocate a new buffer for each read as done by 
libuv). So what I would suggest is the following:


  // task
  blocking_read(socket, buffer, ...)
// this will register socket with the schedulers event queue 
(if not yet done) and block.
// once the scheduler will receive an data is available 
event from the kernel

// it will unblock the task.
// then the task will do an non-blocking read() on it's own.


I'm not that familiar with the uv API. Is there a distinct 'data 
available' event that happens before we start reading? I've been 
assuming that, as you say, we have to control over when the read 
events happen, so we would need to check whether the task initiating 
this read was currently waiting for data, and either buffer it or 
context switch to the task depending on its state.


No there isn't! The reason why, as far as I understand it, lies in 
the way Windows handles reads. In UNIX you get notified, when you can 
read, while in Windows,
you get notified when a read completed, so you are basically doing 
the read asynchronously in the background (saving you another context 
switch to the kernel).
I think this is called Proactor (the UNIX-way is called Reactor). 
libuv wants to do this in a platform-independent way, where the 
programmer who uses libuv does

not have to care about which platform he is working with.

So when we think about this sequence in libuv

  uv_read_start(fd)
  - on_read_cb gets triggered
  uv_read_stop(fd)

what it does internally is the following:

UNIX:

  register event for `fd` in event queue
  epoll()
- allocate buffer
- read(fd, nonblocking)
- call on_read_cb
   unregister event

Windows:

  allocate buffer
  start asynchronous read request
  wait for completion (of any outstanding I/O)
  - call on_read_cb

I think libuv is doing too much here. For example, if I don't want to 
remove the socket from the event
queue, just disable the callback, then this is not possible. I'd 
prefer when I could just tell libuv that
I am interested in event X (on Windows: I/O completion, on UNIX: I/O 
availability).


I think a simple hack would be to store the buffer address and size 
of buffer in the uv_handle_t structure:


struct our_handle {
  uv_handle_t handle;
  void *buffer;
  size_t buffer_size;
}

and then have the alloc_cb return that:

static uv_buf_t alloc_cb(uv_handle_t *handle, size_t suggested_size)
{
  struct our_handle *h = (struct our_handle*)handle;
  return uv_buf_init(h-buffer, h-buffer_size);
}

You specify the alloc_cb in uv_read_start(). The only thing that you 
need to consider
is that when on_read_cb gets called, you better call uv_read_stop(), 
otherwise

the buffer could be overwritten the next time.

Well, yes, this should work for both UNIX and Windows. If you need 
specific help, let me know.
I've been hacking a lot with libuv lately and I can't wait using 
async I/O in rust (which actually

performs well).



Is it possible to do this optimization later or do we need to plan for 
this ahead of time? I would prefer to use the uv API as it's presented 
to start with.


I welcome any help here. One important and big step we need to get 
through before trying to integrate uv into the scheduler is to create 
safe Rust bindings

Re: [rust-dev] Problem with conflicting implementations for traits

2013-01-29 Thread Michael Neumann

Am 26.01.2013 19:20, schrieb Steven Blenkinsop:

You could define an `enum DefaultT= T`


Hm, can you make an example? How will that work? How do I use that?

Michael



On Friday, 25 January 2013, Michael Neumann wrote:

Hi,

I am getting the following error:

msgpack.rs:545:0: 555:1 error: conflicting implementations for a trait
msgpack.rs:545 http://msgpack.rs:545 pub implD: DecoderWithMap,
msgpack.rs:546 http://msgpack.rs:546 K: serialize::DecodableD,
msgpack.rs:547 http://msgpack.rs:547 V: serialize::DecodableD
~[(K,V)]: serialize::DecodableD {
msgpack.rs:548 http://msgpack.rs:548 static fn decode(self, d:
D) - ~[(K,V)] {
msgpack.rs:549 http://msgpack.rs:549 do d.read_map |len| {
msgpack.rs:550 http://msgpack.rs:550 do vec::from_fn(len) |i| {
...
msgpack.rs:539:0: 543:1 note: note conflicting implementation here
msgpack.rs:539 http://msgpack.rs:539 pub implD: DecoderWithMap,
T T: serialize::DecodableD {
msgpack.rs:540 http://msgpack.rs:540 static fn decode(self, d:
D) - T {
msgpack.rs:541 http://msgpack.rs:541
serialize::Decodable::decode(d as serialize::Decoder)
msgpack.rs:542 http://msgpack.rs:542 }
msgpack.rs:543 http://msgpack.rs:543 }


It's obvious that the two trait implementations conflict, as the
one (for T) is
more general as the other (for ~[(K,V)]). Is there anything I can
do to fix it?
I have found this discussion [1] but I see no solution to the problem.

For msgpack, I want to support maps. They are specially encoded,
so I need a
special Decoder (serialize::Decoder does not support maps in any
way). Above I
tried to extend the serialize::Decoder trait for read_map() and
read_map_elt(),
leading to DecoderWithMap:

pub trait DecoderWithMap : serialize::Decoder {
fn read_mapT(self, f: fn(uint) ⟶  T) ⟶  T;
fn read_map_eltT(self, _idx: uint, f: fn() ⟶  T) ⟶  T;
}

Then I tried to implement Decodable for ~[(K,V)] (which I want to
use as a rust
representation as a map; here I'd probably run into problems again as
serializer defines a generic implementation for ~[] and for tuples...
this at least I could solve by using a different type).

Now I would need to reimplement Decodable for any type I use, so I
tried
to use the second generic trait implementation. But this is where
it failed
with a conflict.

Would it be possible to override a standard (more generic) trait
implementation,
either implicitly (like C++ is doing) or explictly?

Best,

Michael

[1]: https://github.com/mozilla/rust/issues/3429

___
Rust-dev mailing list
Rust-dev@mozilla.org
https://mail.mozilla.org/listinfo/rust-dev



___
Rust-dev mailing list
Rust-dev@mozilla.org
https://mail.mozilla.org/listinfo/rust-dev


[rust-dev] Illegal borrow unless pure

2013-01-28 Thread Michael Neumann

Hi,

I am trying to get the following example to work. What I find strange 
is, that
I can call vec::push in fn main(), but when I do the same from fn 
pushit(), it fails

with:

t.rs:6:17: 6:24 error: illegal borrow unless pure: unique value in 
aliasable, mutable location

t.rs:6   vec::push(mut a.arr[0], 3);
^~~
t.rs:6:2: 6:11 note: impure due to access to impure function
t.rs:6   vec::push(mut a.arr[0], 3);
 ^

Example:

struct A {
  arr: ~[ ~[int] ]
}

fn pushit(a: mut A) /*unsafe*/ {
  vec::push(mut a.arr[0], 3);
}

fn main() {
  let mut a: A = A {arr: ~[ ~[1,2,3], ~[3,4,5] ] };
  vec::push(mut a.arr[0], 3); // WORKS
  pushit(mut a); // DOES NOT work!!!
  error!(%?, a);
}

I am a bit lost here. When I use unsafe it works, but is it safe???

Best,

  Michael
___
Rust-dev mailing list
Rust-dev@mozilla.org
https://mail.mozilla.org/listinfo/rust-dev


Re: [rust-dev] Misc questions

2013-01-26 Thread Michael Neumann

Am 25.01.2013 01:37, schrieb Patrick Walton:

On 1/24/13 3:55 PM, Michael Neumann wrote:

Hi,

Again a couple of random question...

* Would it be possible to optimize this kind of enum (two cases, where
one case contains a borrowed pointer)
into a simple pointer, where None would be represented as the null 
pointer?


enum OptionA {
None,
Some(~A)
}

As the pointer to A can never be null it should be possible. This
probably wouldn't affect performance much,
but when storing it into an Array that would save a lot of space
(basically cut down space usage half).


Yes. This has been on the agenda for years. The reason why we don't 
make any guarantees as to the memory layout for enums is precisely so 
that we can implement optimizations like this.


Great to know that this will eventually be implemented.


* match() statements. I think the order in which the matches are
performed are important. But when I have
a very simple statement like this:

match io.read_char() as u8 {
0x0c = ...,
0x0d = ...,
0x0f .. 0x1a =
...
}

will the compiler construct an efficient goto jump table or will it
construct sequential if statements instead?
´ My question is if it makes sense to reorder more frequent cases to the
top or not.


LLVM will construct a jump table. I've verified this in my NES emulator.


Great. Hopefully it merges common statements as well. That is for
  0x00 .. 0x0f = io::println(...)
it don't generate 15 separate io::println instructions. I assume it
generates a table which contains IP offsets.



Also I wonder why I get a non-exhaustive patterns error message for
this one:

match c as u8 {
0 .. 255 = 1
}


The exhaustiveness checker currently doesn't know about integer 
ranges. This is probably a bug.


It's unituitive, so I think it's a bug :)


* Using str::as_bytes()

I cannot get str::as_bytes working. The example in the documention is
not working for several reasons (wrong syntax...)

I tried this:

fn write(buf: ~[u8]) {
io::println(fmt!(%?, buf));
}

fn main() {
let mystr = ~Hello World;
do str::as_bytes(mystr) |bytes| {
write(*bytes);
}
}

But get the compiler error:

t.rs:8:10: 8:16 error: moving out of dereference of immutable  pointer
t.rs:8 write(*bytes);
^~


I think you want `[u8]`.


Of course! I feel little stupid now *g*.


* What exaclty is the semantic of as? Is it like a C-cast?

Imagine if I have

let b: u8 = 255;
let s: i8 = b as i8;

This gives -1 for s. But when I do b as i32, it gives 255.
If I want to keep the sign I have to do (b as i8) as i32.


It's supposed to be like a C cast. This seems like a bug to me.


Hm, for me it makes sense somehow.

I think that every cast from unsigned to signed (or vice versa)
will first extend the size to the requested size so that:

  u8 as i32 equivalent to (u8 as u32) as i32

and this is clearly different to (u8 as i8) as i32, because
i8 as i32 will sign-extend, i.e. keep the upper bit.

Thanks for your answers,

  Michael
___
Rust-dev mailing list
Rust-dev@mozilla.org
https://mail.mozilla.org/listinfo/rust-dev


Re: [rust-dev] Misc questions

2013-01-26 Thread Michael Neumann

Am 26.01.2013 12:28, schrieb Michael Neumann:
Another question: When a task sends a message to another task, and 
this task is waiting exactly for this event, will it directly switch 
to that task, or will it buffer the message?
Sometimes this could be quite handy and efficient. I rember this was 
done in the L4 microkernel (www.l4ka.org), which only allowed 
synchronous IPC. It could make sense to provide a
send_and_receive directive, which sends to the channel and lets the 
scheduler know that it is now waiting for a message to receive from 
another port. So send_and_receive could
directly switch to the other task, and when this does a send back to 
the calling task, it will switch back to it. If you don't have 
send_and_receive as atomic operation, there

is no way to switch back to the other task, as it might still be running.


as it might still be running is here of course wrong (as we switched 
to another thread). What I wanted to say is, that it is not waiting for 
any event, so it is not in a blocking state, so that

we cannot directly switch back (matching the recv() and the send()).

Ideally the task that wants to read would do the non-blocking I/O 
itself, and the scheduler would just notify when it can read. But I 
think this is not possible with libuv as you
have no control over when to read (except using uv_read_start() / 
_stop). I think this would be much more efficient and even more powerful 
(one can read directly into a buffer...
there is no need to allocate a new buffer for each read as done by 
libuv). So what I would suggest is the following:


  // task
  blocking_read(socket, buffer, ...)
// this will register socket with the schedulers event queue (if 
not yet done) and block.
// once the scheduler will receive an data is available event 
from the kernel

// it will unblock the task.
// then the task will do an non-blocking read() on it's own.

Basically it's the same what libuv does internally on it's own, just 
that the responsibility for doing the read's for example is
moved into the task itself, so there is no longer a need for an I/O task 
and we gain full control of the asynchronous reads.


The advantage is:

  * we no longer need messages for I/O.
  * more flexibility
  * much better memory usage (no need to copy anymore)
  * the design is much easier and better to understand,
 libraries become so much easier

Maybe that's just what you want to implement with the scheduler rewrite?

Best,

  Michael
___
Rust-dev mailing list
Rust-dev@mozilla.org
https://mail.mozilla.org/listinfo/rust-dev


Re: [rust-dev] Misc questions

2013-01-26 Thread Michael Neumann

Am 26.01.2013 13:01, schrieb Michael Neumann:

Am 26.01.2013 12:28, schrieb Michael Neumann:
Another question: When a task sends a message to another task, and 
this task is waiting exactly for this event, will it directly switch 
to that task, or will it buffer the message?
Sometimes this could be quite handy and efficient. I rember this was 
done in the L4 microkernel (www.l4ka.org), which only allowed 
synchronous IPC. It could make sense to provide a
send_and_receive directive, which sends to the channel and lets the 
scheduler know that it is now waiting for a message to receive from 
another port. So send_and_receive could
directly switch to the other task, and when this does a send back to 
the calling task, it will switch back to it. If you don't have 
send_and_receive as atomic operation, there
is no way to switch back to the other task, as it might still be 
running.


as it might still be running is here of course wrong (as we switched 
to another thread). What I wanted to say is, that it is not waiting 
for any event, so it is not in a blocking state, so that

we cannot directly switch back (matching the recv() and the send()).

Ideally the task that wants to read would do the non-blocking I/O 
itself, and the scheduler would just notify when it can read. But I 
think this is not possible with libuv as you
have no control over when to read (except using uv_read_start() / 
_stop). I think this would be much more efficient and even more 
powerful (one can read directly into a buffer...
there is no need to allocate a new buffer for each read as done by 
libuv). So what I would suggest is the following:


  // task
  blocking_read(socket, buffer, ...)
// this will register socket with the schedulers event queue (if 
not yet done) and block.
// once the scheduler will receive an data is available event 
from the kernel

// it will unblock the task.
// then the task will do an non-blocking read() on it's own.

Basically it's the same what libuv does internally on it's own, just 
that the responsibility for doing the read's for example is
moved into the task itself, so there is no longer a need for an I/O 
task and we gain full control of the asynchronous reads.


The advantage is:

  * we no longer need messages for I/O.
  * more flexibility
  * much better memory usage (no need to copy anymore)
  * the design is much easier and better to understand,
 libraries become so much easier


* and message passing could be done synchronous, i.e. very fast :)


___
Rust-dev mailing list
Rust-dev@mozilla.org
https://mail.mozilla.org/listinfo/rust-dev


[rust-dev] Misc questions

2013-01-24 Thread Michael Neumann

Hi,

Again a couple of random question...

* Would it be possible to optimize this kind of enum (two cases, where 
one case contains a borrowed pointer)

into a simple pointer, where None would be represented as the null pointer?

enum OptionA {
None,
Some(~A)
}

As the pointer to A can never be null it should be possible. This 
probably wouldn't affect performance much,
but when storing it into an Array that would save a lot of space 
(basically cut down space usage half).


* match() statements. I think the order in which the matches are 
performed are important. But when I have

a very simple statement like this:

match io.read_char() as u8 {
0x0c = ...,
0x0d = ...,
0x0f .. 0x1a =
...
}

will the compiler construct an efficient goto jump table or will it 
construct sequential if statements instead?
´ My question is if it makes sense to reorder more frequent cases to the 
top or not.


Also I wonder why I get a non-exhaustive patterns error message for 
this one:


match c as u8 {
0 .. 255 = 1
}

* Using str::as_bytes()

I cannot get str::as_bytes working. The example in the documention is 
not working for several reasons (wrong syntax...)


I tried this:

fn write(buf: ~[u8]) {
io::println(fmt!(%?, buf));
}

fn main() {
let mystr = ~Hello World;
do str::as_bytes(mystr) |bytes| {
write(*bytes);
}
}

But get the compiler error:

t.rs:8:10: 8:16 error: moving out of dereference of immutable  pointer
t.rs:8 write(*bytes);
^~

* A ~str is internally represented by an ~[u8] vector.
It is basically a heap-allocated

struct rust_vec {
size_t fill;
size_t alloc;
uint8_t data[];
}

When I correctly read the code the string is allocated in-place, i.e. 
for a string of size 5,
you will allocate sizeof(struct rust_vec) + 5 + 1 bytes. So the data 
pointer points past the
data. As a reallocation can change the pointer to the rust_vec, I know 
understand why
I have to pass sometimes a mut ~[T]into a function. In case the 
reallocation returns a new

pointer, the passed pointer has to be updated.

I guess slices use the same rust_vec struct, but allocated on the stack, 
where data points to

another ~vectors data.

What I don't understand is the following comment for struct rust_vec:

size_t fill; // in bytes; if zero, heapified

Please correct me if I am wrong.

* There is a severe performance bug in TcpSocketBuf.read(). I am trying 
to fix it right now myself,
once I am done, I will do another post. This explains why I get very bad 
network I/O performance.
Basically the function copies the internal buffer over and over again, 
once for each call.
This is especially bad when using read_line(), as it calls read() for 
every byte.


* What exaclty is the semantic of as? Is it like a C-cast?

Imagine if I have

let b: u8 = 255;
let s: i8 = b as i8;

This gives -1 for s. But when I do b as i32, it gives 255.
If I want to keep the sign I have to do (b as i8) as i32.

* I don't like the way libuv is currently integrated into the system. It 
works, but performance is
quite low and IMHO the blocking interface is not very usable. For 
example I want to write a process
that accepts messages from other processes, and then writes something to 
the socket or reads from
the socket. This will currently not work, as reading from the socket 
will block the process, and

then no more requests can be sent to the process.
So instead of using the read() / write() API of an io::Reader, I'd 
prefer to expose the read/write
events of libuv via messages (this is already done between the iotask 
and the read()/write() methods,

but it is not accessible to the end-user).

So instead of:

io.read(...)

one would simply write:

readport.recv()

The same for writes. EOF results in closing the readport. The question 
is how these messages

should look like to be usable for the programmer (how to handle errors?).

What do you think?

Actually there would be connecting ports, which receive events whenever 
a new connection is established.
A successfully established connection would then be represented by a 
readport and writechannel.


* I'd like to know more how the task scheduler and the pipes work 
together. Is there any info available somewhere?
Also, if I would create a native pthread in C, could I simply call an 
external rust function?


Best,

Michael
___
Rust-dev mailing list
Rust-dev@mozilla.org
https://mail.mozilla.org/listinfo/rust-dev


[rust-dev] Trying to get simple TCP server working

2012-12-26 Thread Michael Neumann

Hi,

I am trying to write a very simple TCP server (code given below), which 
just reads from a
socket, but somehow the read() blocks forever. Any idea what I am doing 
wrong?
I also tried to create a task for each new incoming connection, but the 
same happens.

I actually found this example on the internet...

When I do wget http://127.0.0.1:4000/; it prints

  - Server is listening
  - New client
  - Accepted!
  - Unwrapped

and then it blocks forever. I also cannot create new connections at this 
point.


Best,

  Michael


/*
 * Simple TCP server
 */
extern mod std;
use std::net::tcp;
use std::net::ip;
use std::uv;

fn main() {
tcp::listen(ip::v4::parse_addr(127.0.0.1), 4000, 100, 
uv::global_loop::get(),

|_comm_chan|{
error!(Server is listening);
},
|new_client, _comm_chan|{
  error!(New client);
let result = tcp::accept(new_client);
if result.is_ok(){
error!(Accepted!);
let socket = result::unwrap(move result);
error!(Unwrapped);
// Now do stuff with this socket
let data = socket.read(100); // XXX: This blocks
io::println(fmt!(%?, data));
}else{
error!(Not accepted!);
}
  } */
});
}


___
Rust-dev mailing list
Rust-dev@mozilla.org
https://mail.mozilla.org/listinfo/rust-dev


[rust-dev] Misc questions and ideas

2012-12-23 Thread Michael Neumann
Hi,

I've spent the last days hacking in Rust and a few questions and ideas
have accumulated over that time.

* If I use unique ~pointers, there is absolutely no runtime overhead,
  so neither ref-counting nor GC is involved, right?

* Heap-allocated pointers incur ref-counting. So when I pass a
  @pointer, I will basically pass a

struct heap_ptr {ptr: *byte, cnt: uint}

  around. Right?

* vec::build_sized() somehow seems to be pretty slow. When I use it,
  instead of a for() loop, my rust-msgpack library slows down by 
  factor 2 for loading msgpack data.

  Also, I would have expected that vec::build_sized() will call my
  supplied function n times. IMHO the name is little bit
  misleading here.

* I do not fully understand the warning of the following script:

  fn main() {
let bytes =
  io::read_whole_file(path::Path(/tmp/matching.msgpack)).get();
  }

  t2.rs:2:14: 2:78 warning: instantiating copy type parameter with a not
  implicitly copyable type t2.rs:2   let bytes =
  io::read_whole_file(path::Path(/tmp/matching.msgpack)).get();
  ^~~~

  Does it mean that it will copy the ~str again? When I use pattern
  matching instead of get(), I don't get this warning, but it seems to
  be slower. Will it just silence the warning???

* This is also strange to me:

  fn nowarn(bytes: [u8]) {}

  fn main() {
let bytes = ~[1,2,3];
nowarn(bytes);
let br = io::BytesReader { bytes: bytes, pos: 0 }; // FAILS
  }

  t.rs:6:36: 6:41 error: mismatched types: expected `/[u8]` but found
  `~[u8]` ([] storage differs: expected  but found ~) t.rs:6   let br =
  io::BytesReader { bytes: bytes, pos: 0 }; ^

  It implicitly converts the ~pointer into a borrowed pointer when
  calling the function, but the same does not work when using the
  BytesReader struct. I think, I should use a make_bytes_reader
  function, but I didn't found one.

* String literals seem to be not immutable. Is that right. That means
  they are always heap allocated. I wished they were immutable, so
  that writing ~my string is stored in read-only memory.

  I never thought this would be possible:

  let s = ~my string;
  let mut s2 = s;
  s2[0] = 'c' as u8;

  Is there a way how a function which takes a ~str can state that it
  will not modify the content?

  In this regard I very much like the way the D language handles this.
  It uses const to state that it won't modify the value, while the
  value itself may be mutable. Then there is immutable, and a value
  declared as such will not change during the whole lifetime. 

  Of course in Rust, thanks to unique pointers, there is less need for
  immutability, as you cannot share a unique pointer between threads.

* Appending to strings. It's easy to push an element to an array by
  doing:

  let mut v: ~[int] = ~[1,2];
  v.push(3);
  v.push(4);

  But when I want to append to a string, I have to write:

  let mut s: ~str = ~;
  let mut s = str::append(s, abc);
  let mut s = str::append(s, def);

  I found this a bit counter-intuitive. I know there exists +=, but
  this will always create a new string. A  operator would be really
  nice to append to strings (or to arrays).

* Default initializers for structs. Would be nice to specify them like:

  struct S {a: int = 4, b: int = 3};

  I know I can use the .. notation, and this is very cool and more
  flexible, but I will have to type in a lot of code if the struct get
  pretty large.

  const DefaultS = S{a: 4, b: 3}; // imagine this has 100 fields :)
  let s = S{a: 4, ..DefaultS};

* Metaprogramming

  Given an arbitrary struct S {...} with some fields, it would be nice
  to somehow derive S.serialize and S.deserialize functions
  automatically. Are there any ideas how to do that? In C++ I use the
  preprocessor and templates for that. In D, thanks to
  compile-time-code-evaluation, I can write code that will introspect
  the struct during compile-time and then generate code.

  I guess I could write a macro like:

  define_ser_struct!(S, field1, int, field2, uint, ...)

  which would generate the struct S and two functions for
  serialization. Would that be possible with macros?

Thanks in advance,

  Michael


___
Rust-dev mailing list
Rust-dev@mozilla.org
https://mail.mozilla.org/listinfo/rust-dev


Re: [rust-dev] Misc questions and ideas

2012-12-23 Thread Michael Neumann
Am Sun, 23 Dec 2012 12:20:07 -0500
schrieb Patrick Walton pwal...@mozilla.com:

 On 12/23/12 10:43 AM, Michael Neumann wrote:
  Hi,

 [...]
 
  * I do not fully understand the warning of the following script:
 
 fn main() {
   let bytes =
 io::read_whole_file(path::Path(/tmp/matching.msgpack)).get();
 }
 
 t2.rs:2:14: 2:78 warning: instantiating copy type parameter with
  a not implicitly copyable type t2.rs:2   let bytes =
 io::read_whole_file(path::Path(/tmp/matching.msgpack)).get();
 ^~~~
 
 Does it mean that it will copy the ~str again? When I use pattern
 matching instead of get(), I don't get this warning, but it
  seems to be slower. Will it just silence the warning???
 
 Yes, it means it will copy the string again. To avoid this, you want 
 result::unwrap() or option::unwrap() instead. I've been thinking for 
 some time that .unwrap() should change to .get() and .get() should 
 change to .copy_value() or something.

That's strange. If I use result::unwrap() it is consistently becoming
much slower! But the warning goes away. While get() is faster, but
there is this warning. Btw, there is also no .unwrap(), just
result::unwrap(). I believe that unwrap() is copying, while get() is
passing a reference somehow.

Michael
___
Rust-dev mailing list
Rust-dev@mozilla.org
https://mail.mozilla.org/listinfo/rust-dev


Re: [rust-dev] net::tcp::TcpSocket slow?

2012-12-22 Thread Michael Neumann

Am 21.12.2012 05:17, schrieb Patrick Walton:

I just profiled this. Some thoughts:

On 12/20/12 9:12 PM, Brian Anderson wrote:

First, stack switching. Switching between Rust and C code has bad
performance due to bad branch prediction. Some workloads can spend
10% of their time stalling in the stack switch.


This didn't seem too high, actually. It should only be ~20,000 stack 
switches (read and write) if we solve the following issue:



Second, working with uv involves sending a bunch of little work units to
a dedicated uv task. This is because callbacks from uv into Rust *must
not fail* or the runtime will crash. Where typical uv code runs directly
in the event callbacks, Rust dispatches most or all of that work to
other tasks. This imposes significant context switching and locking
overhead.


This is actually the problem. If you're using a nonblocking I/O 
library (libuv) for a fundamentally blocking workload (sending lots of 
requests to redis and blocking on the response for each one), *and* 
you're multiplexing userland green threads on top of it, then you're 
going to get significantly worse performance than you would if you had 
used a blocking I/O setup. We can make some of the performance 
differential up by switching uv over to pipes, and maybe we can play 
dirty tricks like having the main thread spin on the read lock so that 
we don't have to fall into the scheduler to punt it awake, but I still 
don't see any way we will make up the 10x performance difference for 
this particular use case without a fundamental change to the 
architecture. Work stealing doesn't seem to be a viable solution here 
since the uv task really needs to be one-task-per-thread.


Maybe the best thing is just to make the choice of nonblocking versus 
blocking I/O a choice that tasks can make on an individual basis. It's 
a footgun to be sure; if you use blocking I/O you run the risk of 
starving other tasks on the same scheduler to death, so perhaps we 
should restrict this mode to schedulers with 1:1 scheduling. But this 
would be in line with the general principle that we've been following 
that the choice of 1:1 and M:N scheduling should be left to the user, 
because there are performance advantages and disadvantages to each mode.


Once this sort of switch is implemented, I would suspect the 
performance differential between Ruby and Rust to be much less.


So I think I should benchmark it against Erlang for example or any other 
evented language which also do message passing instead of direct callbacks.
I can imagine that if I would use libuv directly (lets say in C), and as 
such avoid message sending and scheduling, it would have similar 
performance to the blocking solution.

Would you agree?

The best thing I can do is to use blocking I/O here anyway as it's 
better to have just one connection to Redis and multiplex that, so I can 
easily use one native thread for that.
I am just very new to Rust, and the only thing I found was tcp_net. So I 
think I should define my own FFI socket calls, right?


Thanks!

Best,

  Michael
___
Rust-dev mailing list
Rust-dev@mozilla.org
https://mail.mozilla.org/listinfo/rust-dev


[rust-dev] Warn about implicit integer conversion

2012-12-18 Thread Michael Neumann

Hi,

  let a: u8 = 10_000; // this does not fit inside u8!
  io::println(fmt!(%?, a)); // print 10

I would have expected that rust would warn me if I try to assign an 
integer constant that doesn't fit into the types range.

Maybe there exists a warning that I can enable?

Best,

  Michael
___
Rust-dev mailing list
Rust-dev@mozilla.org
https://mail.mozilla.org/listinfo/rust-dev


[rust-dev] Reading shared immutable data

2012-12-17 Thread Michael Neumann

Hi,

We have a very huge immutable data structure that we want to share 
(read-only) between many light-weight threads.
From what I have seen, I should use Arc. Is there any other way to 
share the data between threads?

And when using Arc, can I access the data in parallel by all threads?

Best regards,

  Michael


___
Rust-dev mailing list
Rust-dev@mozilla.org
https://mail.mozilla.org/listinfo/rust-dev


Re: [rust-dev] Reading shared immutable data

2012-12-17 Thread Michael Neumann

Am 18.12.2012 03:11, schrieb Patrick Walton:

On 12/17/12 6:03 PM, Michael Neumann wrote:

Hi,

We have a very huge immutable data structure that we want to share
(read-only) between many light-weight threads.
 From what I have seen, I should use Arc. Is there any other way to
share the data between threads?


You can also:

* Use a reader-writer lock (RWLock). This is still safe.


I will look into this.

* Use unsafe code by casting to an unsafe pointer and sending the 
unsafe pointer over a channel; do this only as a last resort.


But don't I get into problems with GC when I do that? So I create the 
data structure heap allocated in one thread, then get an unsafe pointer 
to it and sent
this to all other threads. Of course in the originating thread I need to 
keep the reference to the data, otherwise the unsafe pointer will point 
to garbage.


* Turn your shared state into a task and have other tasks access the 
data by sending it messages. This is the classical actor model 
solution, but usually ARC will be more efficient.


But this doesn't allow for parallelism, and that's what we want.




And when using Arc, can I access the data in parallel by all threads?


Yes. The only synchronization cost you'll pay is the cost of an atomic 
CPU instruction whenever you send the data.


I would just send the data once at thread creation. Hm, I have to play 
with that.


Thanks a lot!

Michael

___
Rust-dev mailing list
Rust-dev@mozilla.org
https://mail.mozilla.org/listinfo/rust-dev